linux进程间通信之Posix 信号量用法详解代码举例

Posix信号量不同于System V信号量的信号量集,Posix信号量是单一的信号量,分为有名信号量和无名信号量。
Posix有名信号量是使用Posix IPC名字标示的信号量,可用于进程和线程间的同步;Posix无名信号量是指基于内存的信号量,存放在共享内存区中,用于进程与线程间的同步。

Posix有名信号量可以是内核维护,也可以在文件系统中维护,这取决于信号量对应的路径名是否映射到了真正的磁盘文件上,如果有映射到则在文件系统中维护,否则在内核中维护,Posix有名信号量由函数sem_open(),sem_close(),sem_unlink(),sem_wait(),sem_trywait(),sem_post(),sem_getvalue()来操作使用。

Posix无名信号量根据sem_init()函数调用时的输入参数不同而分为进程间共享和线程间共享,函数原型int sem_init(sem_t *sem,int shared,unsigned int value); 的第二个参数shared若为0,则表示是线程间共享;若shared是1,则表示是进程间共享,同时第一个参数变量sem_t数据类型变量sem必须驻留在所有希望共享它的进程所共享的内存区中。Posix无名信号量由函数sem_init(),sem_destroy(),sem_wait(),sem_trywait(),sem_post(),sem_getvalue()来操作使用。

Posix信号量相关函数的原型及头文件:
#include <semaphore.h>
sem_t *sem_open(const char*name,int oflag,.../*mode_t mode, unsigned int value*/);
功能:创建一个新的有名信号量或打开一个已存在的有名信号量
返回值:若成功返回指向信号量的指针,该指针用作sem_close(),sem_wait(),sem_trywait(),sem_post,sem_getvalue()的参数;若出错返回SEM_FAILED.
参数:name为路径名;oflag可以是0,O_CREAT或O_CREAT|O_EXCL;mode参数可选是指定权限位,在O_CREAT是有效;value参数可选是指定信号量的初始值,不能超过SEM_VALUE_MAX,二值信号量的初始值通常为1,计数信号量初始值通常大于1。

int sem_close(sem_t *sem);
功能:关闭由sem_open()打开的有名信号量。
返回值:若成功返回0,若失败返回-1

int sem_unlink(const char *name);
功能:从系统中真正删除信号量
返回值:若成功返回0,若失败返回-1

int sem_wait(sem_t *sem);
功能:测试指定信号量的值,如果值大于0,则减1并立即返回;如果值等于0,则调用的进程或线程阻塞进入睡眠,直到该值变为大于0,此时会再减1,函数随后返回。这种“测试病减1”的操作必须是原子的。
返回值:成功返回0,出错返回-1

int sem_trywait(sem_t *sem);
功能:与sem_wait()相同,只是当所测试的指定信号量是0时,并不阻塞进入睡眠,而是返回一个EAGAIN错误。
返回值:成功返回0,出错返回-1

int sem_post(sem_t *sem);
功能:把所指定的信号量值加1,然后唤醒正在等待该信号量值变为正数的任意进程或线程。
返回值:成功返回0,出错返回-1

int sem_getvalue(sem_t *sem, int *valp);
功能:获取指定信号量的当前值存入valp指针中,如果信号量已上锁,则获取值为0或某个负数,绝对值是等待该信号量解锁的线程数。
返回值:成功返回0,出错返回-1.

int sem_int(sem_t *sem, int shared, unsigned int value);
功能:初始化Posix共享内存的无名信号量。
返回值: 出错返回-1.
参数:sem是信号量的指针;shared为0是线程共享,为1是进程共享(sem需驻留共享内存);value是初始化值。

int sem_destory(sem_t *sem);
功能:摧毁sem_init()初始化的无名信号量。
返回值:成功返回0,出错返回-1
代码举例,父子进程采用二值信号量sem_test.c:

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <sys/types.h>
  4. #include <unistd.h>
  5. #include <semaphore.h>
  6. #include <fcntl.h>
  7. #define USE_POSIX_SEM 1
  8. #define MYSEM "/mysem"
  9. #define RUN_TIMES 5
  10. int main(void)
  11. {
  12. #if USE_POSIX_SEM
  13. sem_t *semId;
  14. int val;
  15. //sem_unlink(MYSEM);
  16. semId=sem_open(MYSEM,O_CREAT,0666,0);
  17. if(SEM_FAILED==semId)
  18. {
  19. printf("sem open failed!\n");
  20. return 0;
  21. }
  22. sem_getvalue(semId,&val);
  23. printf("sem_val init=%d\n",val);
  24. sem_post(semId);
  25. sem_getvalue(semId,&val);
  26. printf("sem_val after post=%d\n",val);
  27. #endif
  28. int pid=fork();
  29. if (0==pid)
  30. {
  31. int i;
  32. #if USE_POSIX_SEM
  33. sem_wait(semId);
  34. #endif
  35. for(i=0;i<RUN_TIMES;i++)
  36. {
  37. printf("child running!\n");
  38. sleep(1);
  39. }
  40. #if USE_POSIX_SEM
  41. sem_post(semId);
  42. #endif
  43. printf("child end\n");
  44. exit(0);
  45. }
  46. else if (pid>0)
  47. {
  48. int i;
  49. #if USE_POSIX_SEM
  50. sem_wait(semId);
  51. #endif
  52. for(i=0;i<RUN_TIMES;i++)
  53. {
  54. printf("parent running!\n");
  55. sleep(1);
  56. }
  57. #if USE_POSIX_SEM
  58. sem_post(semId);
  59. #endif
  60. printf("parent end\n");
  61. }
  62. waitpid(pid,NULL,0);
  63. printf("progam finished\n");
  64. #if USE_POSIX_SEM
  65. sem_close(semId);
  66. sem_unlink(MYSEM);
  67. #endif
  68. return 0;
  69. }

复制代码

运行结果:
$ ./a.out
sem_val init=0
sem_val after post=1
parent running!
parent running!
parent running!
parent running!
parent running!
parent end
child running!
child running!
child running!
child running!
child running!
child end
progam finished

可以看出,父进程先执行,执行5次打印后post 信号量后,子进程才执行。

如果关闭Posix 信号量,条件编译宏设为“#define USE_POSIX_SEM 0”,运行结果为:
$ ./a.out
parent running!
child running!
parent running!
child running!
parent running!
child running!
parent running!
child running!
child running!
parent running!
parent end
child end
progam finished

可以看到父子进程交替执行,存在竞争关系。

原文地址:https://www.cnblogs.com/wudymand/p/9226476.html

时间: 2024-10-11 18:28:18

linux进程间通信之Posix 信号量用法详解代码举例的相关文章

Linux进程间通信与线程间同步详解(全面详细)

引用:http://community.csdn.net/Expert/TopicView3.asp?id=4374496linux下进程间通信的几种主要手段简介: 1. 管道(Pipe)及有名管道(named pipe):管道可用于具有亲缘关系进程间的通信,有名管道克服了管道没有名字的限制,因此,除具有管道所具有的功能外,它还允许无亲缘关系进程间的通信:   2. 信号(Signal):信号是比较复杂的通信方式,用于通知接受进程有某种事件发生,除了用于进程间通信外,进程还可以发送信号给进程本身

linux dd命令参数及用法详解---用指定大小的块拷贝一个文件(也可整盘备份)

linux dd命令参数及用法详解---用指定大小的块拷贝一个文件 日期:2010-06-14 点击:3830 来源: 未知 分享至: linux dd命令使用详解 dd 的主要选项: 指定数字的地方若以下列字符结尾乘以相应的数字: b=512, c=1, k=1024, w=2, xm=number m if=file 输入文件名,缺省为标准输入. of=file 输出文件名,缺省为标准输出. ibs=bytes 一次读入 bytes 个字节(即一个块大小为 bytes 个字节). obs=b

Linux tar 命令参数及用法详解--Linux打包备份命令

linux tar命令参数及用法详解--linux打包备份命令 tar命令 tar - tar 档案文件管理程序的 GNU 版本.下面将逐个介绍其含义tar [-cxtzjvfpPN] 文件与目录 ....常用参数:-c :建立一个压缩文件的参数指令(create 的意思):-x :解开一个压缩文件的参数指令!-t :查看 tarfile 里面的文件!特别注意,在参数的下达中, c/x/t 仅能存在一个!不可同时存在!因为不可能同时压缩与解压缩.-z :是否同时具有 gzip 的属性?亦即是否需

linux cp命令参数及用法详解---linux 复制文件命令cp

linux cp命令参数及用法详解---linux 复制文件命令cp [[email protected]Linux ~]# cp [-adfilprsu] 来源档(source) 目的檔(destination)[[email protected]linux ~]# cp [options] source1 source2 source3 -. directory参数:-a :相当于 -pdr 的意思:-d :若来源文件为连结文件的属性(link file),则复制连结文件属性而非档案本身:-

(转)linux traceroute命令参数及用法详解--linux跟踪路由命令

linux traceroute命令参数及用法详解--linux跟踪路由命令 原文:http://blog.csdn.net/liyuan_669/article/details/25362505 通过traceroute我们可以知道信息从你的计算机到互联网另一端的主机是走的什么路径.当然每次数据包由某一同样的出发点(source)到达某一同样的目的地(destination)走的路径可能会不一样,但基本上来说大部分时候所走的路由是相同的.linux系统中,我们称之为traceroute,在MS

Linux fdisk命令参数及用法详解---Linux磁盘分区管理命令fdisk

fdisk 命令 linux磁盘分区管理 用途:观察硬盘之实体使用情形与分割硬盘用. 使用方法: 一.在 console 上输入 fdisk -l /dev/sda ,观察硬盘之实体使用情形. 二.在 console 上输入 fdisk /dev/sda,可进入分割硬盘模式. 1. 输入 m 显示所有命令列示. 2. 输入 p 显示硬盘分割情形. 3. 输入 a 设定硬盘启动区. 4. 输入 n 设定新的硬盘分割区. 4.1. 输入 e 硬盘为[延伸]分割区(extend). 4.2. 输入 p

Linux quota命令参数及用法详解---Linux磁盘配额限制设置和查看命令

功能说明:显示磁盘已使用的空间与限制. 语 法:quota [-quvV][用户名称...] 或 quota [-gqvV][群组名称...] 补充说明:执行quota指令,可查询磁盘空间的限制,并得知已使用多少空间. 参 数:  -g   列出群组的磁盘空间限制.  -q   简明列表,只列出超过限制的部分.  -u   列出用户的磁盘空间限制.  -v   显示该用户或群组,在所有挂入系统的存储设备的空间限制.  -V   显示版本信息. 在网络管理的工作中,由于硬盘的资源是有限的,常常需要

linux chsh命令参数及用法详解(linux设置系统shell命令)

使用权限:所有使用者 命令:chsh  用法:shell>> chsh  说明:更改使用者 shell 设定  范例:  shell>> chsh  Changing fihanging shell for user1  Password: [del]  New shell [/bin/tcsh]: ### [是目前使用的 shell]  [del]  shell>> chsh -l ### 展示 /etc/shells 档案内容  /bin/bash  /bin/sh

linux expr命令参数及用法详解

expr用法 expr命令一般用于整数值,但也可用于字符串.一般格式为: #expr argument operator argument expr也是一个手工命令行计数器. #$expr 10 + 10 20 #$expr 1500 + 900 2500 #$expr 30 / 3 10 #$expr 30 / 3 / 2 5 (注意运算符左右都有空格) 使用乘号时,必须用反斜线屏蔽其特定含义.因为shell可能会误解显示星号的意义. #$expr 30 * 3 90 17.5.1 增量计数