You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于信号量的共享内存同步: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.

Step 1: Define Shared Structures & Sync Primitives

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 matrix
  • sem_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"
Step 2: Producer (PR) Code

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;
}
Step 3: Consumer (CO) Code

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;
}
Key Implementation Notes
  • Synchronization Guarantee: The semaphores enforce strict write-then-read order—sem_empty blocks the producer until the consumer finishes reading, and sem_full blocks 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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.22 08:41:55