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

C语言如何使用semaphores(信号量)对共享缓冲区加锁实现同步

问题原因
  • 你当前的代码属于典型的多进程竞态问题:共享缓冲区没有访问控制,多个读写进程可以同时操作缓冲区,读写操作中途会被其他进程打断,因此出现0和1混杂的输出结果。
  • 你要求的同步逻辑本质是两个规则:
    1. 缓冲区互斥访问:同一时间只能有一个进程执行读或者写操作
    2. 操作顺序保证:0的写入、读取全流程完成后,再执行1的相关操作
解决方案实现

我们采用POSIX无名信号量实现同步,由于信号量需要在多个进程间共享,因此需要将信号量存储在共享内存区域中。

完整修改后代码

#include <stdio.h>
#include <signal.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <sys/times.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys/wait.h>
#include <semaphore.h> // 新增信号量头文件

#define FILE_SIZE 11
#define NO_PROC   10

int DelayCount = 0;

int readerID = 0;
int writerID = 0;

char* shared_buffer;
sem_t* shared_mutex; // 互斥信号量,控制缓冲区访问
sem_t* write0_done;  // 顺序控制信号量,标记writer0写+读完成

const int LOOP_TIME = 3;

/* The reader */
void reader() {
    int i,j;
    char results[FILE_SIZE];

    printf("Reader %d (pid = %d) arrives\n", readerID, getpid());

    for (i=0; i<LOOP_TIME; i++) {  
        printf("   Reader %d starts round %d\n", readerID,i);
        // 申请缓冲区访问权限
        sem_wait(shared_mutex);
        
        /* read data from shared data */
        for (j=0; j<FILE_SIZE; j++) {
            results[j] = shared_buffer[j];
            sleep(2);
        }

        /* display result */
        results[j] = 0;
        printf("Reader %d (round %d) gets results : %s\n", readerID, i, results);
        
        // 释放缓冲区访问权限
        sem_post(shared_mutex);
        
        // 第一轮读完0后,标记0操作完成
        if(i == 0) {
            sem_post(write0_done);
        }
        sleep(1);
   }
}

/* The writer */
void writer() {
    int i,j;
    char data[FILE_SIZE];

    for (j=0; j<FILE_SIZE-1; j++) {
        data[j]= writerID + '0';
    }
    data[j]= 0;

    printf("Writer %d (pid = %d) arrives, writing %s to buffer\n",
          writerID, getpid(), data);

    // 写1的进程先等待0的写+读全流程完成
    if(writerID == 1) {
        sem_wait(write0_done);
    }

    for (i=0; i<LOOP_TIME; i++){
        printf("   Write %d starts round %d\n", writerID,i);
        // 申请缓冲区访问权限
        sem_wait(shared_mutex);
        
        /* write to shared buffer */
        for (j=0; j<FILE_SIZE-1; j++) {
            shared_buffer[j]= data[j];
            sleep(1);  
        }

        printf("Writer %d (round %d) finishes\n", writerID, i);
        // 释放缓冲区访问权限
        sem_post(shared_mutex);
        sleep(1);
  }
 }

/* creating readers and writers */
void create_reader() {
    if (0 == fork()) {
        reader();
        exit(0);
    }
    readerID++;
}

void create_writer() {
    if (0 == fork()) {
        writer();
        exit(0);
    }
    writerID++;
}

/* main */
int main() {
    char InitData[]="0000000000\n";
    int i;
    int fd;
    // 共享内存大小扩容:缓冲区大小 + 两个信号量的大小
    int shm_size = FILE_SIZE + sizeof(sem_t) * 2;

    /* creates a memory region shared by all child processes */
    fd = open("race.dat", O_RDWR | O_CREAT | O_TRUNC, 0600);
    if ( fd < 0 ) {
        perror("race.dat ");
        exit(1);
    }
    // 扩容文件到共享内存大小
    ftruncate(fd, shm_size);
    write(fd, InitData, FILE_SIZE);
    unlink("race.dat"); 

    void *shm_ptr = mmap(0, shm_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0);
    if ( shm_ptr == (caddr_t) -1) {
        perror("mmap");
        exit(2);
    }
    // 分配共享内存空间:前两个位置存信号量,后面存缓冲区
    shared_mutex = (sem_t*)shm_ptr;
    write0_done = (sem_t*)shm_ptr + 1;
    shared_buffer = (char*)shm_ptr + sizeof(sem_t)*2;

    // 初始化信号量:第二个参数1代表进程间共享
    sem_init(shared_mutex, 1, 1); // 互斥信号量初始值1
    sem_init(write0_done, 1, 0); // 顺序信号量初始值0,等待0操作完成

    /* Create readers and writes */
    create_reader();
    sleep(1);
    create_writer();
    sleep(1);
    create_writer();

    /* Wait until all children terminate */
    for (i=0; i<(readerID+writerID); i++) {
        wait(NULL);
    }

    // 销毁信号量、释放资源
    sem_destroy(shared_mutex);
    sem_destroy(write0_done);
    munmap(shm_ptr, shm_size);
    close(fd);
    return 0;
}

运行说明

编译时需要链接pthread库:
gcc your_code.c -o sync_demo -lpthread

内容的提问来源于stack exchange,提问作者ark

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 20:06:03