📜  fork()和使用它创建的内存共享黑白进程(1)

📅  最后修改于: 2023-12-03 14:41:18.855000             🧑  作者: Mango

Fork() and Creating Shared Memory with Black-and-White Process

Fork() is a system call used for creating new processes in Unix-like operating systems. It allows a process (called parent) to create a copy of itself (called child), and both parent and child processes run concurrently.

One interesting use case of fork() is creating shared memory between processes. Shared memory allows two or more processes to access the same region of memory for exchanging data. In this example, we will create a simple black-and-white image processing program using shared memory and fork().

Creating Shared Memory

To create shared memory, we can use the system calls shmget(), shmat(), and shmdt(). shmget() creates a new shared memory segment or opens an existing one, shmat() maps the shared memory segment to the process's address space, and shmdt() detaches the shared memory segment from the process.

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>

#define SHM_SIZE 1024 // Shared memory size in bytes

int main() {
    int shmid; // Shared memory ID
    key_t key = 1234; // Shared memory key
    char *shm; // Shared memory address

    // Create or open shared memory segment
    if ((shmid = shmget(key, SHM_SIZE, IPC_CREAT | 0666)) < 0) {
        perror("shmget");
        exit(1);
    }

    // Attach shared memory segment to process's address space
    if ((shm = shmat(shmid, NULL, 0)) == (char *) -1) {
        perror("shmat");
        exit(1);
    }

    // Write to shared memory
    sprintf(shm, "Hello, World!");

    // Detach shared memory segment from process's address space
    shmdt(shm);

    return 0;
}
Forking Processes

Now that we can create and use shared memory in a process, we can create a child process using fork(). The child process will inherit a copy of the parent process's address space, including the shared memory segment.

#include <unistd.h> // For fork() and getpid()

int main() {
    int pid = fork(); // Create child process

    if (pid < 0) { // Error
        perror("fork");
        exit(1);
    } else if (pid == 0) { // Child process
        printf("Child process with PID %d\n", getpid());
        // Read from shared memory and process image
        // ...
        exit(0);
    } else { // Parent process
        printf("Parent process with PID %d created child process with PID %d\n", getpid(), pid);
        // Write to shared memory and process image
        // ...
        wait(NULL); // Wait for child process to terminate
        exit(0);
    }
}

We can use getpid() to get the process ID of the current process and wait() to wait for a child process to terminate.

Black-and-White Image Processing

Now let's put it all together to create a simple black-and-white image processing program using shared memory and fork(). In this program, the parent process reads an image file and writes the grayscale image to shared memory, and the child process reads the grayscale image from shared memory and writes the black-and-white image to a new file.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/wait.h>
#include <string.h>
#include <errno.h>

#define SHM_SIZE 1000000 // Shared memory size in bytes
#define IMAGE_WIDTH 800 // Image width in pixels
#define IMAGE_HEIGHT 600 // Image height in pixels
#define PIXEL_SIZE 3 // RGB pixel size in bytes
#define GRAYSCALE_SIZE (IMAGE_WIDTH * IMAGE_HEIGHT) // Grayscale image size in bytes
#define BW_THRESHOLD 0.5 // Black-and-white threshold

// Convert RGB pixel to grayscale
unsigned char rgb_to_gray(unsigned char r, unsigned char g, unsigned char b) {
    return (r * 0.299 + g * 0.587 + b * 0.114);
}

int main(int argc, char *argv[]) {
    if (argc != 3) {
        printf("Usage: %s <input_image> <output_image>\n", argv[0]);
        exit(1);
    }

    int shmid; // Shared memory ID
    key_t key = 1234; // Shared memory key
    unsigned char *shm; // Shared memory address

    // Open input image file
    FILE *in_file = fopen(argv[1], "rb");
    if (!in_file) {
        printf("Failed to open input image file: %s\n", strerror(errno));
        exit(1);
    }

    // Create or open shared memory segment
    if ((shmid = shmget(key, SHM_SIZE, IPC_CREAT | 0666)) < 0) {
        perror("shmget");
        exit(1);
    }

    // Attach shared memory segment to process's address space
    if ((shm = shmat(shmid, NULL, 0)) == (unsigned char *) -1) {
        perror("shmat");
        exit(1);
    }

    // Read input image and convert to grayscale
    unsigned char pixel[3];
    unsigned char *grayscale = shm;
    for (int i = 0; i < IMAGE_HEIGHT; i++) {
        for (int j = 0; j < IMAGE_WIDTH; j++) {
            fread(&pixel, PIXEL_SIZE, 1, in_file);
            grayscale[i * IMAGE_WIDTH + j] = rgb_to_gray(pixel[0], pixel[1], pixel[2]);
        }
    }
    fclose(in_file);

    // Fork child process
    int pid = fork();
    if (pid < 0) {
        perror("fork");
        exit(1);
    } else if (pid == 0) { // Child process
        printf("Child process with PID %d\n", getpid());

        // Open output image file
        FILE *out_file = fopen(argv[2], "wb");
        if (!out_file) {
            printf("Failed to open output image file: %s\n", strerror(errno));
            exit(1);
        }

        // Read grayscale image from shared memory and write black-and-white image to file
        unsigned char bw_pixel;
        for (int i = 0; i < IMAGE_HEIGHT; i++) {
            for (int j = 0; j < IMAGE_WIDTH; j++) {
                bw_pixel = (grayscale[i * IMAGE_WIDTH + j] / 255.0 > BW_THRESHOLD) ? 255 : 0;
                fwrite(&bw_pixel, 1, 1, out_file);
                fwrite(&bw_pixel, 1, 1, out_file);
                fwrite(&bw_pixel, 1, 1, out_file);
            }
        }
        fclose(out_file);

        // Detach shared memory segment from process's address space
        shmdt(shm);

        exit(0);
    } else { // Parent process
        printf("Parent process with PID %d created child process with PID %d\n", getpid(), pid);

        // Wait for child process to terminate
        wait(NULL);

        // Detach shared memory segment from process's address space
        shmdt(shm);

        exit(0);
    }
}

This program reads the input image file specified by the first command-line argument, converts it to grayscale, writes the grayscale image to shared memory, forks a child process, waits for the child process to terminate, reads the grayscale image from shared memory in the child process, and writes the black-and-white image to the output image file specified by the second command-line argument.

Conclusion

Fork() is a powerful system call that allows us to create new processes and share memory between them. In this example, we showed how to use fork() and shared memory to create a simple black-and-white image processing program. There are many other use cases for fork() and shared memory, so keep exploring!