php中文网 | cnphp.com

 找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 771|回复: 0

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

[复制链接]

3138

主题

3148

帖子

1万

积分

管理员

Rank: 9Rank: 9Rank: 9

UID
1
威望
0
积分
7946
贡献
0
注册时间
2021-4-14
最后登录
2024-11-21
在线时间
763 小时
QQ
发表于 2022-2-24 08:39:55 | 显示全部楼层 |阅读模式
这篇帖子主要是记录一下自己使用信号量遇到的坑。

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

    如果A,B两个进程各自独立操作的话,很容易出现下列情况。 看哪个进程先抢占到这个buffer,由于write和read这个buffer都会阻塞另一个进程,所以可能会出现一个进程一直写数据,然后读进程会读到多条数据。
image.png
解决方案,利用linux POSIX中的semaphore完成读写同步。设置两个信号量semwr,semrd;semwr控制读,初始化值设置为1(in unlocked state),semrd控制写,初始化设置为0(in locked state)。并由读进程释放写锁,由写进程释放读锁。(一个信号量是无法完成读写同步的)。

    读进程:
[mw_shl_code=c,true]#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;

}[/mw_shl_code]
写进程:
[mw_shl_code=c,true]#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;

}

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

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

    即 gcc XXXX.c -pthread -o xxx

    由此实现了同步读写:
image.png





上一篇:
下一篇:个人收款码可继续使用!赶紧停下申请商家收款码步伐
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|php中文网 | cnphp.com ( 赣ICP备2021002321号-2 )

GMT+8, 2024-11-21 23:03 , Processed in 0.302996 second(s), 40 queries , Gzip On.

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2020, Tencent Cloud.

申明:本站所有资源皆搜集自网络,相关版权归版权持有人所有,如有侵权,请电邮(fiorkn@foxmail.com)告之,本站会尽快删除。

快速回复 返回顶部 返回列表