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

首先是需求:创建两个进程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)。并由读进程释放写锁,由写进程释放读锁。(一个信号量是无法完成读写同步的)。

读进程:

  1. #include <fcntl.h>
  2. #include <sys/stat.h>
  3. #include <semaphore.h>
  4. #include <stdio.h>
  5. #include <unistd.h>
  6. #include <sys/types.h>
  7. #include <errno.h>
  8. #include <string.h>
  9. #define MAXLINE 100
  10. #define CONTEXT "HELLO WORLD"
  11. #define FILENAME "MY_FIFO"
  12. #define LOOP 200
  13. #define SEMRD "sem_read"
  14. #define SEMWR "sem_write"
  15. int main(int argc,char *argv[]){
  16. /* create the named pipe fifo*/
  17. int fd;
  18. int ret;
  19. ret = mkfifo(FILENAME,0666);
  20. if(ret!=0){
  21. perror("mkfifo");
  22. }
  23. fd=open(FILENAME,O_RDONLY);
  24. if(fd<0){
  25. perror("open fifo");
  26. }
  27. /*open the semaphore*/
  28. sem_t *semwr,*semrd;
  29. int pwr,prd;
  30. semwr=sem_open(SEMWR,O_CREAT,0666,1);
  31. semrd=sem_open(SEMRD,O_CREAT,0666,0);
  32. if(semwr==(void*)-1 ||semrd==(void*)-1){
  33. perror("sem_open failure");
  34. }
  35. printf("sem address\n");
  36. printf("semwr=%p\n",semwr);
  37. printf("semrd=%p\n",semrd);
  38. /*get this value*/
  39. sem_getvalue(semwr,&pwr);
  40. sem_getvalue(semrd,&prd);
  41. printf("wr value=%d\n",pwr);
  42. printf("rd value=%d\n",prd);
  43. /* communication period*/
  44. int i=LOOP;
  45. while (i--){
  46. /*lock*/
  47. sem_wait(semrd);
  48. char recv[MAXLINE]={0};
  49. read(fd,recv,sizeof(recv));
  50. printf("read from my_fifo buf=[%s]\n",recv);
  51. sem_post(semwr);
  52. }
  53. /*close the file*/
  54. close(fd);
  55. sem_close(semwr);
  56. sem_close(semrd);
  57. /* release resource*/
  58. unlink(FILENAME);
  59. sem_unlink(SEMWR);
  60. sem_unlink(SEMRD);
  61. return 0;
  62. }

写进程:

  1. #include <fcntl.h>
  2. #include <sys/stat.h>
  3. #include <semaphore.h>
  4. #include <stdio.h>
  5. #include <unistd.h>
  6. #include <sys/types.h>
  7. #include <errno.h>
  8. #include <string.h>
  9. #define MAXLINE 100
  10. #define CONTEXT "HELLO WORLD"
  11. #define FILENAME "MY_FIFO"
  12. #define LOOP 200
  13. #define SEMRD "sem_read"
  14. #define SEMWR "sem_write"
  15. int main(int argc,char *argv[]){
  16. /* create the named pipe fifo*/
  17. int fd;
  18. int ret;
  19. ret = mkfifo(FILENAME,0666);
  20. if(ret!=0){
  21. perror("mkfifo");
  22. }
  23. fd=open(FILENAME,O_WRONLY);
  24. if(fd<0){
  25. perror("open fifo");
  26. }
  27. /*open the semaphore*/
  28. sem_t *semwr,*semrd;
  29. int pwr,prd;
  30. semwr=sem_open(SEMWR,O_CREAT,0666,1);
  31. semrd=sem_open(SEMRD,O_CREAT,0666,0);
  32. if(semwr==(void*)-1 ||semrd==(void*)-1){
  33. perror("sem_open failure");
  34. }
  35. printf("sem address\n");
  36. printf("semwr=%p\n",semwr);
  37. printf("semrd=%p\n",semrd);
  38. /*get this value*/
  39. sem_getvalue(semwr,&pwr);
  40. sem_getvalue(semrd,&prd);
  41. printf("wr value=%d\n",pwr);
  42. printf("rd value=%d\n",prd);
  43. /* communication period*/
  44. int i=LOOP;
  45. char send[MAXLINE]=CONTEXT;
  46. while (i--){
  47. /*lock*/
  48. sem_wait(semwr);
  49. write(fd,send,strlen(send));
  50. printf("send to my_fifo buf\n",send);
  51. sem_post(semrd);
  52. }
  53. /*close the file*/
  54. close(fd);
  55. sem_close(semwr);
  56. sem_close(semrd);
  57. /* release resource*/
  58. unlink(FILENAME);
  59. sem_unlink(SEMWR);
  60. sem_unlink(SEMRD);
  61. return 0;
  62. }

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

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

gcc XXXX.c -pthread -o xxx

由此实现了同步读写:

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

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

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

利用信号量semaphore实现两个进程读写同步 Linux C的更多相关文章

  1. linux下的进程通信之信号量semaphore

    概念: IPC 信号量和内核信号量非常相似,是内核信号量的用户态版本. 优点:每个IPC信号量可以保护一个或者多个信号量值的集合,而不像内核信号量一样只有一个值,这意味着同一个IPC资源可以保护多个独 ...

  2. linux内核剖析(十)进程间通信之-信号量semaphore

    信号量 什么是信号量 信号量的使用主要是用来保护共享资源,使得资源在一个时刻只有一个进程(线程)所拥有. 信号量的值为正的时候,说明它空闲.所测试的线程可以锁定而使用它.若为0,说明它被占用,测试的线 ...

  3. GIL与普通互斥锁区别,死锁现象,信号量,event事件,进程池与线程池,协程

    GIL与普通互斥锁区别 GIL锁和互斥锁的异同点 相同: 都是为了解决解释器中多个线程资源竞争的问题 异: 1.互斥锁是Python代码层面的锁,解决Python程序中多线程共享资源的问题(线程数据共 ...

  4. 并发编程~~~多线程~~~守护线程, 互斥锁, 死锁现象与递归锁, 信号量 (Semaphore), GIL全局解释器锁

    一 守护线程 from threading import Thread import time def foo(): print(123) time.sleep(1) print('end123') ...

  5. Java基础教程:多线程基础(6)——信号量(Semaphore)

    Java基础教程:多线程基础(6)——信号量(Semaphore) 信号量 信号量(Semaphore)由一个值和一个指针组成,指针指向等待该信号量的进程.信号量的值表示相应资源的使用情况.信号量S≥ ...

  6. linux信号量之进程间同步

    概念 linux信号量: 允许多个线程同时进入临界区,可以用于进程间的同步. 和互斥锁(mutex)的区别: 互斥锁只允许一个线程进入临界区. 所在头文件: semaphore.h 主要函数 初始化函 ...

  7. 信号量 Semaphore

    一.简介         信号量(Semaphore),有时被称为信号灯,是在多线程环境下使用,负责协调各个线程, 以保证它们能够正确.合理的使用公共资源. Semaphore可以控制某个资源可被同时 ...

  8. java笔记--对信号量Semaphore的理解与运用

    java Semaphore 信号量的使用: 在java中,提供了信号量Semaphore的支持. Semaphore类是一个计数信号量,必须由获取它的线程释放, 通常用于限制可以访问某些资源(物理或 ...

  9. python 守护进程、同步锁、信号量、事件、进程通信Queue

    一.守护进程 1.主进程创建守护进程 其一:守护进程会在主进程代码执行结束后就终止 其二:守护进程内无法再开启子进程,否则抛出异常:AssertionError: daemonic processes ...

随机推荐

  1. 51 Nod 1134 最长递增子序列 (动态规划基础)

    原题链接:1134 最长递增子序列 题目分析:长度为  的数列  有多达  个子序列,但我们应用动态规划法仍可以很高效地求出最长递增子序列().这里介绍两种方法. 先考虑用下列变量设计动态规划的算法. ...

  2. 【记录一个问题】linux + opencv + gpu视频解码,好不容易编译通过,运行又coredump了

    1.首先编译了opencv + cuda   编译选项中使用了以下关于cuvid库的内容: //"nvcuvid" libraryCUDA_nvcuvid_LIBRARY:FILE ...

  3. 基于SpringBoot如何实现一个点赞功能?

    基于SpringBoot如何实现一个点赞功能? 解析: 基于 SpringCloud, 用户发起点赞.取消点赞后先存入 Redis 中,再每隔两小时从 Redis 读取点赞数据写入数据库中做持久化存储 ...

  4. golang中匿名函数的应用-回调函数-闭包

    package main import ( "fmt" "strconv" ) type funcType func(int, int) int // 自定义函 ...

  5. Linux 配置mysql 免安装版。

    二.Linux配置 mysql ? 1.linux配置mysql(要求全部使用免安装版) 5.1.从官网下载mysql5.tar.gz 5.2.使用xftp把mysql的压缩包上传到服务器上 5.3. ...

  6. SpringBoot 简单介绍

    一.springboot是啥? 1.什么是springboot? 1.1springboot是spring生态圈的一个轻量级框架,换句话说springboot就是spring,是spring的一个衍生 ...

  7. web.xml 配置文件?

    <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="http:// ...

  8. CKKS Part4: CKKS的乘法和重线性化

    本文翻译于CKKS EXPLAINED, PART 4: MULTIPLICATION AND RELINEARIZATION,主要介绍CKKS方案中的密文乘法和重线性化技术 介绍 在上一篇 CKKS ...

  9. APC 篇——总结与提升

    写在前面   此系列是本人一个字一个字码出来的,包括示例和实验截图.由于系统内核的复杂性,故可能有错误或者不全面的地方,如有错误,欢迎批评指正,本教程将会长期更新. 如有好的建议,欢迎反馈.码字不易, ...

  10. AT2650 [ARC077C] guruguru

    可以发现,如果我们枚举每个理想亮度 \(X\) 然后再求在这个理想亮度情况下的答案是非常难维护的. 不妨反过来,考虑每个位置 \(i, i + 1\) 之间对每个理想亮度 \(X\) 减少次数的贡献. ...