Keywords: Shared Memory | Linux System Programming | Inter-Process Communication | mmap | fork | C Programming
Abstract: This article provides an in-depth exploration of two primary methods for implementing shared memory in C on Linux systems: mmap and shmget. Through detailed code examples and step-by-step explanations, it focuses on how to combine fork() with shared memory to enable data sharing and synchronization between parent and child processes. The paper compares the advantages and disadvantages of the modern mmap approach versus the traditional shmget method, offering best practice recommendations for real-world applications, including memory management, process synchronization, and error handling.
Overview of Shared Memory Technology
In Linux system programming, inter-process communication (IPC) is a critical technical domain. Shared memory, as one of the most efficient IPC mechanisms, allows multiple processes to directly access the same physical memory region, avoiding the overhead of data copying. This article primarily focuses on the modern mmap method while contrasting it with the traditional shmget approach, providing comprehensive implementation solutions.
Implementing Shared Memory with mmap
The mmap system call offers flexible memory mapping capabilities and can create anonymous shared memory regions. This method does not require filesystem support and is suitable for data sharing between parent and child processes.
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
void* create_shared_memory(size_t size) {
// Set memory protection permissions: readable and writable
int protection = PROT_READ | PROT_WRITE;
// Set memory visibility: shared and anonymous
int visibility = MAP_SHARED | MAP_ANONYMOUS;
// Create shared memory region
return mmap(NULL, size, protection, visibility, -1, 0);
}
The above function creates a shared memory region of the specified size. The MAP_SHARED flag ensures the memory region is shared between parent and child processes, while MAP_ANONYMOUS indicates this is an anonymous mapping not dependent on a specific file.
Complete Example with fork() Integration
The following example demonstrates data exchange between parent and child processes using shared memory:
#include <string.h>
#include <unistd.h>
#include <stdio.h>
int main() {
char parent_message[] = "hello"; // Parent process initial message
char child_message[] = "goodbye"; // Child process update message
// Create 128-byte shared memory
void* shmem = create_shared_memory(128);
// Parent process writes initial data
memcpy(shmem, parent_message, sizeof(parent_message));
// Create child process
int pid = fork();
if (pid == 0) {
// Child process code
printf("Child read: %s\n", (char*)shmem);
memcpy(shmem, child_message, sizeof(child_message));
printf("Child wrote: %s\n", (char*)shmem);
} else {
// Parent process code
printf("Parent read: %s\n", (char*)shmem);
sleep(1); // Wait for child process to complete writing
printf("After 1s, parent read: %s\n", (char*)shmem);
}
return 0;
}
Comparison with Traditional shmget Method
In addition to the mmap method, Linux provides the traditional System V shared memory interface. The reference article demonstrates basic usage of shmget:
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/stat.h>
int main() {
int segment_id;
char* shared_memory;
const int shared_segment_size = 0x6400;
// Create shared memory segment
segment_id = shmget(IPC_PRIVATE, shared_segment_size,
IPC_CREAT | IPC_EXCL | S_IRUSR | S_IWUSR);
// Attach to shared memory
shared_memory = (char*) shmat(segment_id, 0, 0);
// Write data
sprintf(shared_memory, "Hello, world.");
// Detach from shared memory
shmdt(shared_memory);
return 0;
}
Analysis of Practical Application Scenarios
Addressing the specific scenario in the user's requirements, we need to store two character pointers: current_path (read-write) and file_name (read-only). Here is the implementation solution:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <unistd.h>
// Define shared data structure
typedef struct {
char current_path[256]; // Current path, modifiable
char file_name[256]; // File name, read-only
} shared_data_t;
int main(int argc, char* argv[]) {
// Create shared memory
shared_data_t* shared_data = (shared_data_t*)
create_shared_memory(sizeof(shared_data_t));
// Initialize data
strcpy(shared_data->current_path, "/home/user");
strcpy(shared_data->file_name, "document.txt");
// Decide whether to create child process based on command line arguments
if (argc > 1 && strcmp(argv[1], "--child") == 0) {
// Child process: read and modify current_path
printf("Child: Current path is %s\n", shared_data->current_path);
printf("Child: File name is %s\n", shared_data->file_name);
// Modify current path
strcpy(shared_data->current_path, "/home/user/documents");
printf("Child: Updated path to %s\n", shared_data->current_path);
} else {
// Parent process
printf("Parent: Initial path: %s\n", shared_data->current_path);
// Create child process
int pid = fork();
if (pid == 0) {
// Child process re-executes itself with --child parameter
execl(argv[0], argv[0], "--child", NULL);
} else {
// Parent process waits and checks updates
sleep(1);
printf("Parent: After child execution, path is: %s\n",
shared_data->current_path);
}
}
return 0;
}
Memory Management and Synchronization Considerations
When using shared memory, the following critical issues must be addressed:
Memory Deallocation: Shared memory created with mmap is automatically released when the process terminates, but explicitly calling munmap is better practice. For shmget, manual invocation of shmctl is required for deletion.
Process Synchronization: Concurrent access to shared memory by multiple processes can cause race conditions. In practical applications, semaphores, mutexes, or other synchronization mechanisms should be used to protect critical sections.
Error Handling: All system calls should check return values. mmap returns MAP_FAILED on failure, shmget returns -1, requiring appropriate error handling logic.
Performance and Applicability Analysis
The mmap method offers several advantages over shmget: simpler API, better flexibility, and better integration with modern Linux kernels. The shmget method remains valuable when compatibility with legacy systems or specific System V IPC features is required.
In actual projects, the choice between methods depends on specific requirements: mmap is recommended for simple parent-child process communication, while complex multi-process systems may need the additional features of shmget.
Conclusion
Shared memory is an efficient inter-process communication mechanism in Linux. Through proper use of mmap or shmget, combined with fork() to create child processes, flexible data sharing can be achieved. The code examples and best practices provided in this article offer a solid foundation for developers to apply these technologies in real-world projects.