含信号量与可变长度数组的共享内存结构体定义及跨进程共享问询
Hey there! Let's work through how to create that shared memory struct for your producer-consumer setup. Your initial idea uses variable-length arrays (VLAs) in the struct, which won't work in standard C—structs can only have a single flexible array as their final member, which doesn't help here with three arrays. Here's a solid approach to make this work:
Step 1: Define the Struct with Shared Semaphores and Array Metadata
Instead of embedding VLAs directly, we'll use pointers in the struct to point to array data stored in the same shared memory block. We'll also include the array dimensions so all processes know how to index the data:
typedef double lr; struct ShMem { sem_t prod; // Producer semaphore sem_t cons; // Consumer semaphore size_t nx; // X dimension for your arrays size_t ny; // Y dimension size_t nz; // Z dimension lr *u_x; // Pointer to u_x array lr *u_y; // Pointer to u_y array lr *u_z; // Pointer to u_z array };
Step 2: Calculate Total Shared Memory Size
We need to allocate enough space to hold the struct plus all three arrays. Calculate the total size like this:
size_t nx = 400, ny = 400, nz = 400; // Calculate element counts for each array size_t u_x_count = (nx + 1) * (ny + 2) * (nz + 2); size_t u_y_count = (nx + 2) * (ny + 1) * (nz + 2); size_t u_z_count = (nx + 2) * (ny + 2) * (nz + 2); // Total shared memory size = struct size + sum of all array sizes size_t total_size = sizeof(struct ShMem) + (u_x_count + u_y_count + u_z_count) * sizeof(lr);
Step 3: Create and Map Shared Memory
Use POSIX shared memory functions (shm_open, mmap) to create and map the memory block. Then initialize the struct's pointers to point to the correct locations in the shared memory:
#include <stdio.h> #include <stdlib.h> #include <sys/mman.h> #include <fcntl.h> #include <sys/stat.h> #include <semaphore.h> #include <unistd.h> int main() { size_t nx = 400, ny = 400, nz = 400; size_t u_x_count = (nx + 1) * (ny + 2) * (nz + 2); size_t u_y_count = (nx + 2) * (ny + 1) * (nz + 2); size_t u_z_count = (nx + 2) * (ny + 2) * (nz + 2); size_t total_size = sizeof(struct ShMem) + (u_x_count + u_y_count + u_z_count) * sizeof(lr); // Create shared memory object int shm_fd = shm_open("/my_prod_cons_shmem", O_CREAT | O_RDWR, 0666); if (shm_fd == -1) { perror("Failed to create shared memory"); exit(EXIT_FAILURE); } // Resize shared memory to our calculated total size if (ftruncate(shm_fd, total_size) == -1) { perror("Failed to resize shared memory"); close(shm_fd); exit(EXIT_FAILURE); } // Map shared memory to process address space struct ShMem *shmem = mmap(NULL, total_size, PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0); if (shmem == MAP_FAILED) { perror("Failed to map shared memory"); close(shm_fd); exit(EXIT_FAILURE); } // Initialize semaphores for inter-process sharing (second arg = 1) if (sem_init(&shmem->prod, 1, 0) == -1) { // Start with 0: consumer waits for producer perror("Failed to initialize prod semaphore"); munmap(shmem, total_size); close(shm_fd); exit(EXIT_FAILURE); } if (sem_init(&shmem->cons, 1, 1) == -1) { // Start with 1: producer can write first perror("Failed to initialize cons semaphore"); sem_destroy(&shmem->prod); munmap(shmem, total_size); close(shm_fd); exit(EXIT_FAILURE); } // Set dimension values in the struct shmem->nx = nx; shmem->ny = ny; shmem->nz = nz; // Calculate pointer positions (arrays start right after the struct) lr *data_start = (lr*)((char*)shmem + sizeof(struct ShMem)); shmem->u_x = data_start; shmem->u_y = data_start + u_x_count; shmem->u_z = shmem->u_y + u_y_count;
Step 4: Access the Arrays Easily
Since the pointers are one-dimensional, use a macro to simplify 3D array-style access:
#define U_X(shm, i, j, k) (shm->u_x[(i)*((shm->ny)+2)*((shm->nz)+2) + (j)*((shm->nz)+2) + (k)]) #define U_Y(shm, i, j, k) (shm->u_y[(i)*((shm->ny)+1)*((shm->nz)+2) + (j)*((shm->nz)+2) + (k)]) #define U_Z(shm, i, j, k) (shm->u_z[(i)*((shm->ny)+2)*((shm->nz)+2) + (j)*((shm->nz)+2) + (k)]) // Example usage: U_X(shmem, 0, 0, 0) = 1.0; printf("u_x[0][0][0] = %lf\n", U_X(shmem, 0, 0, 0));
Step 5: Cleanup Resources
When all processes are done, clean up the shared memory and semaphores:
// Cleanup (run this in the last process to exit) sem_destroy(&shmem->prod); sem_destroy(&shmem->cons); munmap(shmem, total_size); close(shm_fd); shm_unlink("/my_prod_cons_shmem"); return 0; }
Key Notes
- Semaphore Initialization: The second argument to
sem_initmust be1to make the semaphore shared between processes. - Shared Memory Name: All processes must use the same name (e.g.,
/my_prod_cons_shmem) to access the same shared memory block. - Dimension Consistency: Ensure all producer/consumer processes use the same
nx,ny,nzvalues—mismatched dimensions will cause memory access errors.
内容的提问来源于stack exchange,提问作者datapanda

