利用信号量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
由此实现了同步读写:

-----------------------------------------------------------------------------
该文章为原创,转载请注明出处。
-----------------------------------------------------------------------------
利用信号量semaphore实现两个进程读写同步 Linux C的更多相关文章
- linux下的进程通信之信号量semaphore
概念: IPC 信号量和内核信号量非常相似,是内核信号量的用户态版本. 优点:每个IPC信号量可以保护一个或者多个信号量值的集合,而不像内核信号量一样只有一个值,这意味着同一个IPC资源可以保护多个独 ...
- linux内核剖析(十)进程间通信之-信号量semaphore
信号量 什么是信号量 信号量的使用主要是用来保护共享资源,使得资源在一个时刻只有一个进程(线程)所拥有. 信号量的值为正的时候,说明它空闲.所测试的线程可以锁定而使用它.若为0,说明它被占用,测试的线 ...
- GIL与普通互斥锁区别,死锁现象,信号量,event事件,进程池与线程池,协程
GIL与普通互斥锁区别 GIL锁和互斥锁的异同点 相同: 都是为了解决解释器中多个线程资源竞争的问题 异: 1.互斥锁是Python代码层面的锁,解决Python程序中多线程共享资源的问题(线程数据共 ...
- 并发编程~~~多线程~~~守护线程, 互斥锁, 死锁现象与递归锁, 信号量 (Semaphore), GIL全局解释器锁
一 守护线程 from threading import Thread import time def foo(): print(123) time.sleep(1) print('end123') ...
- Java基础教程:多线程基础(6)——信号量(Semaphore)
Java基础教程:多线程基础(6)——信号量(Semaphore) 信号量 信号量(Semaphore)由一个值和一个指针组成,指针指向等待该信号量的进程.信号量的值表示相应资源的使用情况.信号量S≥ ...
- linux信号量之进程间同步
概念 linux信号量: 允许多个线程同时进入临界区,可以用于进程间的同步. 和互斥锁(mutex)的区别: 互斥锁只允许一个线程进入临界区. 所在头文件: semaphore.h 主要函数 初始化函 ...
- 信号量 Semaphore
一.简介 信号量(Semaphore),有时被称为信号灯,是在多线程环境下使用,负责协调各个线程, 以保证它们能够正确.合理的使用公共资源. Semaphore可以控制某个资源可被同时 ...
- java笔记--对信号量Semaphore的理解与运用
java Semaphore 信号量的使用: 在java中,提供了信号量Semaphore的支持. Semaphore类是一个计数信号量,必须由获取它的线程释放, 通常用于限制可以访问某些资源(物理或 ...
- python 守护进程、同步锁、信号量、事件、进程通信Queue
一.守护进程 1.主进程创建守护进程 其一:守护进程会在主进程代码执行结束后就终止 其二:守护进程内无法再开启子进程,否则抛出异常:AssertionError: daemonic processes ...
随机推荐
- 深度介绍Flink在字节跳动数据流的实践
本文是字节跳动数据平台开发套件团队在1月9日Flink Forward Asia 2021: Flink Forward 峰会上的演讲分享,将着重分享Flink在字节跳动数据流的实践. 字节跳动数据流 ...
- WebRTC本地选择codec(web本地模拟)
视频编码后,再进行发送.WebRTC建立视频连接前,可以选择codec.一般来说支持多种codec,以VP8和H264为代表. Codec: 编码译码器,编解码器 示例代码 写一个示例,用户可以在发送 ...
- 【LeetCode】628. 三个数的最大乘积
解题思路 如果数组中全是正数或者全是负数,最大乘积就是最大的三个数的乘积.如果数组中既有正数又有负数,最大乘积可能是三个最大正数乘积,也可能是两个最小负数和最大正数的乘积.遍历数组找到最大的三个数和最 ...
- 图片不清晰?Graphics 高质量绘制
Graphics.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.HighQualityBicubic; Graphics ...
- JUC之线程池的实现原理以及拒绝策略
线程池实现原理 向线程池提交任务后,线程池如何来处理这个任务,之前我们了解了7个参数,我们通过这些参数来串联其线程池的实现原理. 1.在创建了线程池后,开始等待请求 2.当调用execute()方法添 ...
- 记一次简单的Oracle离线数据迁移至TiDB过程
背景 最近在支持一个从Oracle转TiDB的项目,为方便应用端兼容性测试需要把Oracle测试环境的库表结构和数据同步到TiDB中,由于数据量并不大,所以怎么方便怎么来,这里使用CSV导出导入的方式 ...
- 记录一个问题:macos High Sierra 10.13.6 内核内存泄漏,导致内存满而不得不重启
kernel_task进程占用内存10g以上,使用中突然提示内存不足,要求杀死工作进程,不得不强按电源键来关机重启. 升级之前,版本大约是macos High Sierra 10.13.4, 系统频繁 ...
- new实例化和反射实例化有什么区别?
在工厂设计模式中,使用反射实例化,子类可以随便增加,工厂类不需要做任何的修改 使用反射之后最大的好处就是解耦合
- git 撤销,放弃本地修改,放弃已提交修改
一, 未使用 git add 缓存代码时. 可以使用 git checkout -- filepathname (比如: git checkout -- readme.md ,不要忘记中间的 &quo ...
- 如何添加自己的code snippet
好了我们开始说吧 1.先建一个后缀名为.sublime-snippet的文件