linux Posix 信号量

信号量是一种用于提供不同进程间或一个给定进程的不同线程间同步手段的原语。有三种类型:Posix有名信号量,使用Posix IPC名字标识;Posix基于内存的信号量,存放在共享内存区中;System V信号量,在内核中维护。这三种信号量都可用于进程间或线程间的同步。

图1 由两个进程使用的一个二值信号量

图2 由两个进程使用的一个Posix有名二值信号量

图3 由一个进程内的两个线程共享的基于内存的信号量

一个进程可以在某个信号量上执行的三种操作:

1、创建一个信号量,这要求调用者指定初始值,对于二值信号量来说,它通常是1,也可是0。

2、等待一个信号量,该操作会测试这个信号量的值,如果小于0,就阻塞。也称为P操作。

3、挂出一个信号量,该操作将信号量的值加1,也称为V操作。

信号量、互斥锁和条件变量之间的三个差异:

1、互斥锁必须总是给它上锁的线程解锁,信号量的挂出却不必由执行过它的等待操作的同一线程执行。

2、互斥锁要么被锁住,要么被解开。

3、既然信号量有一个与之关联的状态,那么信号量挂出操作总是被记住。然而当向一个条件变量发送信号时,如果没有线程等待在该条件变量上,信号丢失。

Posix提供两类信号量:有名信号量和基于内存的信号量(也称无名信号量)。使用函数如下:

  1. #include <semaphore.h>
  2. /*sem_open创建一个新的有名信号量或打开一个已存在的有名信号量,value参数指定信号量的初始值,返回值是一个指向某个sem_t数据类型的指针,用作其他函数的参数*/
  3. sem_t   *sem_open(const char *name, int oflag, .../*mode_t mode, unsigned int value*/);
  4. int sem_close(sem_t *sem); /*一个进程终止时,内核对其上仍打开着的所有信号量自动执行关闭操作*/
  5. int     sem_unlink(const char *name); /*sem_unlink函数:当引用计数大于0时,name就能从文件系统中删除,然而信号量的析构却要等到最后一个sem_close发生时为止*/
  6. int     sem_wait(sem_t *sem); /*测试所指定信号量的值,大于0,将它减1并返回,等于0,调用线程休眠,直到该值大于0,将它减1,函数随后返回*/
  7. int     sem_trywait(sem_t *sem); /*所指定信号量值为0时,不休眠,而是返回一个EAGAIN错误*/
  8. int     sem_post(sem_t *sem);
  9. int     sem_getvalue(sem_t *sem, int  *valp);/* 由valp指向的整数中返回所指定信号量的当前值。*/

semcreate程序:

  1. #include <semaphore.h>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <unistd.h>
  5. #include <fcntl.h>
  6. #include <sys/stat.h>
  7. #include <sys/types.h>
  8. #define FILE_MODE (S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH)
  9. int
  10. main(int argc, char **argv)
  11. {
  12. int     c, flags;
  13. sem_t   *sem;
  14. unsigned int value;
  15. flags = O_RDWR | O_CREAT;
  16. value = 1;
  17. while((c = getopt(argc, argv, "ei:")) != -1){
  18. switch(c){
  19. case ‘e‘:
  20. flags |= O_EXCL;
  21. case ‘i‘:
  22. value = atoi(optarg);
  23. break;
  24. }
  25. }
  26. if(optind != argc - 1){
  27. printf("usage:semcreate [-e] [-i initalvalue] <name>\n");
  28. return -1;
  29. }
  30. sem = sem_open(argv[optind], flags, FILE_MODE, value);
  31. sem_close(sem);
  32. exit(0);
  33. }

semunlink程序:

  1. #include <semaphore.h>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <unistd.h>
  5. int
  6. main(int argc, char **argv)
  7. {
  8. if(argc != 2){
  9. printf("usage:semunlink <name>.\n");
  10. return -1;
  11. }
  12. sem_unlink(argv[1]);
  13. exit(0);
  14. }

semgetvalue程序:

  1. #include <semaphore.h>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <unistd.h>
  5. int
  6. main(int argc, char **argv)
  7. {
  8. sem_t   *sem;
  9. int     val;
  10. if(argc != 2){
  11. printf("usage:semgetvalue <name>.\n");
  12. return -1;
  13. }
  14. sem = sem_open(argv[1], 0);
  15. sem_getvalue(sem, &val);
  16. printf("value = %d\n", val);
  17. exit(0);
  18. }

semwait程序:

  1. #include <semaphore.h>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <unistd.h>
  5. int
  6. main(int argc, char **argv)
  7. {
  8. sem_t   *sem;
  9. int     val;
  10. if(argc != 2){
  11. printf("usage: semwait <name>");
  12. return -1;
  13. }
  14. sem = sem_open(argv[1], 0);
  15. sem_wait(sem);
  16. sem_getvalue(sem, &val);
  17. printf("pid %ld has semaphore, value = %d\n", (long)getpid(), val);
  18. pause();                /*block until killed*/
  19. exit(0);
  20. }

sempost程序:

  1. #include <semaphore.h>
  2. #include <stdio.h>
  3. #include <stdlib.h>
  4. #include <unistd.h>
  5. int
  6. main(int argc, char **argv)
  7. {
  8. sem_t   *sem;
  9. int     val;
  10. if(argc != 2){
  11. printf("usage:sempost <name>\n");
  12. return -1;
  13. }
  14. sem = sem_open(argv[1], 0);
  15. sem_post(sem);
  16. sem_getvalue(sem, &val);
  17. printf("value = %d\n", val);
  18. exit(0);
  19. }

Posix基于内存的信号量,由应用程序分配信号量的内存空间(也就是分配一个sem_t数据类型的内存空间),然后由系统初始化它们的值。

  1. #include <stmaphore.h>
  2. int sem_init(sem_t *sem, int shared, unsigned int value);  /*出错返回-1*/
  3. int     sem_destroy(sem_t *sem);            <span style="white-space:pre">    </span>/*成功返回0,出错返回-1*/

基于内存的信号量是由sem_init初始化的,sem参数指向应用程序必须分配的sem_t变量。如果shared为0,那么待初始化的信号量是在同一进程的各个线程间共享的,否则该信号量是在进程间共享的。

当不需要使用与有名信号量关联的名字时,可改用基于内存的信号量。彼此无亲缘关系的不同进程需要使用信号量时,通常使用有名信号量。其名字就是各个进程标识信号量的手段。基于内存信号量至少具有进程持续性,然而它们真正的持续性却取决于存放信号量的内存区的类型。只要含有某个基于内存信号量的内存区保持有效,该信号量就一直存在。

进程间共享信号量

进程间共享基于内存信号量的规则很简单:信号量本身必须驻留在由所有希望共享它的进程所共享的内存区中,而且sem_init的第二个参数必须是1。

有名信号量,不同进程总是能够访问同一个有名信号量,只要它们在调用sem_open时指定相同的名字即可。

信号量限制

Posix定义了两个信号量限制:

SEM_NSEMS_MAX 一个进程可同时打开着的最大信号数

SEM_VALUE_MAX 一个信号量的最大值

这两个常值定义在<unistd.h>头文件中,可在运行时通过sysconf函数获取。

时间: 2024-10-18 18:15:05

linux Posix 信号量的相关文章

linux Posix 信号量 二

一.Posix信号量 1.Posix信号量分为两种: 1.   有名信号量:使用Posix IPC名字标识(有名信号量总是既可用于线程间的同步,又可以用于进程间的同步) 2.   内存信号量:存放在共享内存区中(基于内存的信号量则必须在创建时指定成是否在进程间共享,且在所有进程的共享内存区,具有随进程的持续性) Posix信号量不必在内核中维护(System V信号量由内核维护),由可能为路径名的名字来标识. (Posix信号量更常用于进程间同步,互斥锁常用于线程间同步) 2.基本操作: 1. 

linux Posix 信号量 三 (经典例子)

本文将阐述一下信号量的作用及经典例子,当中包括“<越狱>寄信”,“家庭吃水果”,“五子棋”,“接力赛跑”,“读者写者”,“四方恋爱”等 首先,讲 semWait操作(P操作)和semSignal操作(V操作)的一些基本原则.(接下来同意称为P,V操作) 1. P操作,s - -,if(s<0)阻塞自己 2. V操作,s++,if(s<=0)唤醒一个其他进程 3. P,V操作时原语(通俗讲,就是执行PV操作时时不能被打打断的) 4. P,V操作总是成对出现的.P:资源申请/分配:V操

Linux环境编程之同步(四):Posix信号量

信号量是一种用于提供不同进程间或一个给定进程的不同线程间同步手段的原语.有三种类型:Posix有名信号量,使用Posix IPC名字标识:Posix基于内存的信号量,存放在共享内存区中:System V信号量,在内核中维护.这三种信号量都可用于进程间或线程间的同步. 图1 由两个进程使用的一个二值信号量 图2 由两个进程使用的一个Posix有名二值信号量 图3 由一个进程内的两个线程共享的基于内存的信号量 一个进程可以在某个信号量上执行的三种操作: 1.创建一个信号量,这要求调用者指定初始值,对

Linux 内核信号量与用户态信号量(System V&amp;POSIX)总结

一.什么是信号量 信号量的使用主要是用来保护共享资源,使得资源在一个时刻只有一个进程(线程)所拥有. 信号量的值为正的时候,说明它空闲.所测试的线程可以锁定而使用它.若为0,说明它被占用,测试的线程要进入睡眠队列中,等待被唤醒. 二.信号量的分类 在学习信号量之前,我们必须先知道——Linux提供两种信号量: (1) 内核信号量,由内核控制路径使用 (2) 用户态进程使用的信号量,这种信号量又分为POSIX信号量和SYSTEM V信号量. POSIX信号量又分为有名信号量和无名信号量. 有名信号

Linux多线程实践(5) --Posix信号量与互斥量解决生产者消费者问题

Posix信号量 Posix 信号量 有名信号量 无名信号量 sem_open sem_init sem_close sem_destroy sem_unlink sem_wait sem_post 有名信号量 #include <fcntl.h> /* For O_* constants */ #include <sys/stat.h> /* For mode constants */ #include <semaphore.h> sem_t *sem_open(co

Linux互斥与同步应用(四):posix信号量的互斥与同步

[版权声明:尊重原创,转载请保留出处:blog.csdn.net/shallnet 或 .../gentleliu,文章仅供学习交流,请勿用于商业用途] 在前面讲共享内存的IPC时曾说共享内存本身不具备同步机制,如果要实现同步需要使用信号量等手段来实现之,现在我们就来说说使用posix的信号量来实现posix多进程共享内存的同步.其实信号量也可以使用在同一进程的不同线程之间. 信号量是一个包含非负整数的变量,有两个原子操作,wait和post,也可以说是P操作和V操作,P操作将信号量减一,V操作

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

Posix信号量不同于System V信号量的信号量集,Posix信号量是单一的信号量,分为有名信号量和无名信号量.Posix有名信号量是使用Posix IPC名字标示的信号量,可用于进程和线程间的同步:Posix无名信号量是指基于内存的信号量,存放在共享内存区中,用于进程与线程间的同步. Posix有名信号量可以是内核维护,也可以在文件系统中维护,这取决于信号量对应的路径名是否映射到了真正的磁盘文件上,如果有映射到则在文件系统中维护,否则在内核中维护,Posix有名信号量由函数sem_open

linux c编程:Posix信号量

POSIX信号量接口,意在解决XSI信号量接口的几个不足之处: POSIX信号量接口相比于XSI信号量接口,允许更高性能的实现. POSIX信号量接口简单易用:没有信号量集,其中一些接口模仿了我们熟悉的文件系统操作. POSIX信号量删除时的处理更加合理.XSI信号量被删除后,使用该信号量标识符的操作将会出错返回,并将errno设置为EIDRM.而对于POSIX信号量,操作可以继续正常执行,直到对该信号量的最后一个引用被释放. POSIX信号量有两种形式可供选用:有名和无名.它们的区别在于,如何

Linux中信号量处理

参考文章: http://blog.csdn.net/qinxiongxu/article/details/7830537/ 信号量一. 什么是信号量信号量的使用主要是用来保护共享资源,使得资源在一个时刻只有一个进程( 线程)所拥有.信号量的值为正的时候,说明它空闲.所测试的线程可以锁定而使用它.若为0, 说明它被占用,测试的线程要进入睡眠队列中, 等待被唤醒.二. 信号量的分类在学习信号量之前,我们必须先知道—— Linux提供两种信号量:(1) 内核信号量,由内核控制路径使用(2) 用户态进