A Practical Guide to Shared Memory with fork() in Linux C Programming

Nov 19, 2025 · Programming · 15 views · 7.8

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.

Copyright Notice: All rights in this article are reserved by the operators of DevGex. Reasonable sharing and citation are welcome; any reproduction, excerpting, or re-publication without prior permission is prohibited.