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

博客 动态
0 192
羽尘
羽尘 2022-02-23 23:55:44
悬赏:0 积分 收藏

利用信号量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

    由此实现了同步读写:

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

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

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

posted @ 2022-02-23 23:41 aalanwyr 阅读(0) 评论(0) 编辑 收藏 举报
回帖
    羽尘

    羽尘 (王者 段位)

    2335 积分 (2)粉丝 (11)源码

     

    温馨提示

    亦奇源码

    最新会员