• 利用信号量semaphore实现两个进程读写同步 Linux C


        这篇帖子主要是记录一下自己使用信号量遇到的坑。

        首先是需求:创建两个进程A,B。A往buffer中写,B读。两个进程利用命名管道进行通信,并实现读写同步。即A写完后通知B读,B读完后通知A写。

        如果A,B两个进程各自独立操作的话,很容易出现下列情况。 看哪个进程先抢占到这个buffer,由于write和read这个buffer都会阻塞另一个进程,所以可能会出现一个进程一直写数据,然后读进程会读到多条数据。

        解决方案,利用linux POSIX中的semaphore完成读写同步。设置两个信号量semwr,semrd;semwr控制读,初始化值设置为1(in unlocked state),semrd控制写,初始化设置为0(in locked state)。并由读进程释放写锁,由写进程释放读锁。(一个信号量是无法完成读写同步的)。

        读进程:

    #include <fcntl.h>           
    #include <sys/stat.h>        
    #include <semaphore.h>
    #include <stdio.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <errno.h>
    #include <string.h>
    
    
    #define MAXLINE 100
    #define CONTEXT "HELLO WORLD"
    #define FILENAME "MY_FIFO"
    #define LOOP 200
    #define SEMRD "sem_read"
    #define SEMWR "sem_write"
    
    int main(int argc,char *argv[]){
        /* create the named pipe fifo*/
        int fd;
        int ret;
        ret = mkfifo(FILENAME,0666);
        if(ret!=0){
            perror("mkfifo");
        }
        fd=open(FILENAME,O_RDONLY);
        if(fd<0){
            perror("open fifo");
        }
        /*open the semaphore*/
        sem_t *semwr,*semrd;
        int pwr,prd;
        semwr=sem_open(SEMWR,O_CREAT,0666,1);
        semrd=sem_open(SEMRD,O_CREAT,0666,0);
        if(semwr==(void*)-1 ||semrd==(void*)-1){
            perror("sem_open failure");
        }
        printf("sem address\n");
        printf("semwr=%p\n",semwr);
        printf("semrd=%p\n",semrd);
        /*get this value*/
        sem_getvalue(semwr,&pwr);
        sem_getvalue(semrd,&prd);
        printf("wr value=%d\n",pwr);
        printf("rd value=%d\n",prd);
        /* communication period*/
        int i=LOOP;
        while (i--){
            /*lock*/
            sem_wait(semrd);
            char recv[MAXLINE]={0};
            read(fd,recv,sizeof(recv));
            printf("read from my_fifo buf=[%s]\n",recv);
            sem_post(semwr);
        }
        /*close the file*/
        close(fd);
        sem_close(semwr);
        sem_close(semrd);
        /* release resource*/
        unlink(FILENAME);
        sem_unlink(SEMWR);
        sem_unlink(SEMRD);
        return 0;
    
    }

      写进程:

    #include <fcntl.h>           
    #include <sys/stat.h>        
    #include <semaphore.h>
    #include <stdio.h>
    #include <unistd.h>
    #include <sys/types.h>
    #include <errno.h>
    #include <string.h>
    
    #define MAXLINE 100
    #define CONTEXT "HELLO WORLD"
    #define FILENAME "MY_FIFO"
    #define LOOP 200
    #define SEMRD "sem_read"
    #define SEMWR "sem_write"
    
    int main(int argc,char *argv[]){
        /* create the named pipe fifo*/
        int fd;
        int ret;
        ret = mkfifo(FILENAME,0666);
        if(ret!=0){
            perror("mkfifo");
        }
        fd=open(FILENAME,O_WRONLY);
        if(fd<0){
            perror("open fifo");
        }
        /*open the semaphore*/
        sem_t *semwr,*semrd;
        int pwr,prd;
        semwr=sem_open(SEMWR,O_CREAT,0666,1);
        semrd=sem_open(SEMRD,O_CREAT,0666,0);
        if(semwr==(void*)-1 ||semrd==(void*)-1){
            perror("sem_open failure");
        }
        printf("sem address\n");
        printf("semwr=%p\n",semwr);
        printf("semrd=%p\n",semrd);
        /*get this value*/
        sem_getvalue(semwr,&pwr);
        sem_getvalue(semrd,&prd);
        printf("wr value=%d\n",pwr);
        printf("rd value=%d\n",prd);
        /* communication period*/
        int i=LOOP;
        char send[MAXLINE]=CONTEXT;
        while (i--){
            /*lock*/
            sem_wait(semwr);
            write(fd,send,strlen(send));
            printf("send to my_fifo buf\n",send);
            sem_post(semrd);
        }
        /*close the file*/
        close(fd);
        sem_close(semwr);
        sem_close(semrd);
        /* release resource*/
        unlink(FILENAME);
        sem_unlink(SEMWR);
        sem_unlink(SEMRD);
        return 0;
    
    }
    
    

         需要注意的是,POSIX中的信号量是随内核持续的,如果信号量不sem_unlink的话,该命名信号量会常驻在kernel之中,即使进程结束了也会存在,而sem_open创建信号量时,如果该named semaphore存在内核中,你设置的初始化参数是无效的(一定要man 3 sem_open 看看参数的解释,别百度,垃圾文档太多,看官方的最好),所以用完之后需要统一释放资源。

        gcc 编译的时候需要加上 -pthread 

        即 gcc XXXX.c -pthread -o xxx

        由此实现了同步读写:

    -----------------------------------------------------------------------------

    该文章为原创,转载请注明出处。

    -----------------------------------------------------------------------------

  • 相关阅读:
    探秘三维地形瓦片服务:流畅展现全球地貌的秘密揭秘
    影刀连接Mysql数据库
    java-php-python-客户台账管理计算机毕业设计
    ArcGIS软件制作双变量等值区域地图(Bivariate Choropleth Maps)
    餐饮供应链管理系统
    taskset使用和说明
    Xilinx FPGA未使用管脚上下拉状态配置(ISE和Vivado环境)
    把简单留给用户,把复杂交给 AI
    Oracle EBS Interface/API(44)- 销售订单发运明细行拆分
    基于javaweb+jsp的客户关系管理系统CRM(JavaWeb MySQL JSP Bootstrap Servlet SSM SpringBoot)
  • 原文地址:https://www.cnblogs.com/aalan/p/15929788.html