基于信号量的共享内存同步:PR与CO共享3D矩阵同步问题
Alright, let's solve this producer-consumer problem where a producer (PR) owns and updates a 3D matrix in shared memory, and a consumer (CO) only reads it after PR has finished writing. We'll use POSIX shared memory for the matrix and POSIX semaphores to enforce strict write-then-read synchronization.
First, we need a consistent way to represent the 3D matrix in shared memory. We'll wrap its dimensions and data in a struct so both processes can access it uniformly. We'll also use two semaphores to coordinate access:
sem_empty: Starts at 1, signals when PR can write to the matrixsem_full: Starts at 0, signals when CO can read the matrix
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <fcntl.h> #include <sys/mman.h> #include <sys/stat.h> #include <semaphore.h> #include <unistd.h> #include <errno.h> // Define fixed dimensions for the 3D matrix (adjust as needed) #define MAT_DIM1 2 #define MAT_DIM2 3 #define MAT_DIM3 4 // Struct to hold matrix metadata and data in shared memory typedef struct { int dim1; int dim2; int dim3; float data[MAT_DIM1][MAT_DIM2][MAT_DIM3]; } SharedMatrix; // Unique names for shared memory and semaphores (avoid system conflicts) #define SHM_NAME "/shared_3d_mat" #define SEM_EMPTY_NAME "/sem_empty" #define SEM_FULL_NAME "/sem_full"
The producer creates the shared memory, initializes the matrix, and enters an iteration loop where it updates the matrix, then signals the consumer it's ready to read.
int main() { // Create and configure shared memory int shm_fd = shm_open(SHM_NAME, O_CREAT | O_RDWR, 0666); if (shm_fd == -1) { perror("shm_open failed"); exit(EXIT_FAILURE); } // Resize shared memory to fit our matrix struct if (ftruncate(shm_fd, sizeof(SharedMatrix)) == -1) { perror("ftruncate failed"); close(shm_fd); shm_unlink(SHM_NAME); exit(EXIT_FAILURE); } // Map shared memory to the producer's address space SharedMatrix *mat = mmap(NULL, sizeof(SharedMatrix), PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0); if (mat == MAP_FAILED) { perror("mmap failed"); close(shm_fd); shm_unlink(SHM_NAME); exit(EXIT_FAILURE); } // Initialize matrix dimensions mat->dim1 = MAT_DIM1; mat->dim2 = MAT_DIM2; mat->dim3 = MAT_DIM3; // Create semaphores for synchronization sem_t *sem_empty = sem_open(SEM_EMPTY_NAME, O_CREAT, 0666, 1); sem_t *sem_full = sem_open(SEM_FULL_NAME, O_CREAT, 0666, 0); if (sem_empty == SEM_FAILED || sem_full == SEM_FAILED) { perror("sem_open failed"); munmap(mat, sizeof(SharedMatrix)); close(shm_fd); shm_unlink(SHM_NAME); exit(EXIT_FAILURE); } // Iteration loop: update matrix and sync with consumer int iteration = 0; while (iteration < 5) { // Run 5 iterations as an example // Wait for permission to write (sem_empty starts at 1) sem_wait(sem_empty); printf("Producer: Updating matrix (iteration %d)\n", iteration); // Update matrix values with iteration-specific data for (int i = 0; i < mat->dim1; i++) { for (int j = 0; j < mat->dim2; j++) { for (int k = 0; k < mat->dim3; k++) { mat->data[i][j][k] = (float)(iteration * 10 + i + j + k); } } } // Signal consumer that the matrix is ready to read sem_post(sem_full); iteration++; sleep(1); // Simulate work between iterations } // Cleanup resources sem_close(sem_empty); sem_close(sem_full); munmap(mat, sizeof(SharedMatrix)); close(shm_fd); printf("Producer: Finished all iterations\n"); return EXIT_SUCCESS; }
The consumer opens the existing shared memory and semaphores, then enters a loop where it waits for the producer to finish writing, reads the matrix, then signals the producer it can write again.
int main() { // Open shared memory created by the producer int shm_fd = shm_open(SHM_NAME, O_RDONLY, 0666); if (shm_fd == -1) { perror("shm_open failed"); exit(EXIT_FAILURE); } // Map shared memory to the consumer's address space (read-only) SharedMatrix *mat = mmap(NULL, sizeof(SharedMatrix), PROT_READ, MAP_SHARED, shm_fd, 0); if (mat == MAP_FAILED) { perror("mmap failed"); close(shm_fd); exit(EXIT_FAILURE); } // Open semaphores created by the producer sem_t *sem_empty = sem_open(SEM_EMPTY_NAME, 0); sem_t *sem_full = sem_open(SEM_FULL_NAME, 0); if (sem_empty == SEM_FAILED || sem_full == SEM_FAILED) { perror("sem_open failed"); munmap(mat, sizeof(SharedMatrix)); close(shm_fd); exit(EXIT_FAILURE); } // Iteration loop: wait for producer, read matrix, sync back int iteration = 0; while (iteration < 5) { // Match the producer's iteration count // Wait for producer to finish writing sem_wait(sem_full); printf("\nConsumer: Reading matrix (iteration %d)\n", iteration); // Read and print matrix values (replace with your processing logic) for (int i = 0; i < mat->dim1; i++) { for (int j = 0; j < mat->dim2; j++) { printf("Layer %d, Row %d: ", i, j); for (int k = 0; k < mat->dim3; k++) { printf("%.1f ", mat->data[i][j][k]); } printf("\n"); } } // Signal producer that we're done reading, it can write again sem_post(sem_empty); iteration++; sleep(1); // Simulate post-read processing time } // Cleanup and unlink shared resources (since consumer exits last) sem_close(sem_empty); sem_close(sem_full); munmap(mat, sizeof(SharedMatrix)); close(shm_fd); shm_unlink(SHM_NAME); sem_unlink(SEM_EMPTY_NAME); sem_unlink(SEM_FULL_NAME); printf("\nConsumer: Finished all reads\n"); return EXIT_SUCCESS; }
- Synchronization Guarantee: The semaphores enforce strict write-then-read order—
sem_emptyblocks the producer until the consumer finishes reading, andsem_fullblocks the consumer until the producer finishes writing. - Compilation: Compile both programs with the
-lrt(for POSIX shared memory) and-pthread(for semaphores) flags:gcc producer.c -o producer -lrt -pthread gcc consumer.c -o consumer -lrt -pthread - Resource Cleanup: Always unlink shared memory and semaphores after both processes exit to avoid leaving orphaned resources on the system. In this example, the consumer handles unlinking since it exits last.
- Unique Names: Use unique names for shared memory and semaphores to avoid conflicts with other processes on your system.
内容的提问来源于stack exchange,提问作者datapanda

