📅  最后修改于: 2023-12-03 14:41:18.855000             🧑  作者: Mango
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().
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;
}
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.
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.
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!