当前位置:   article > 正文

linux ---17 --18----信号量编程实现_信号量17

信号量17

信号量相当于钥匙,进程A拿钥匙进入临界资源(多个进程都可以进入),B就没有钥匙进去了,只能A出来,B才有钥匙拿进去。

信号量(semaphore)与已经介绍过的 IPC 结构不同,它是一个计数器。信号量用于实现进程间的互斥与同步,而不是用于存储进程间通信数据。

1、特点

  1. 信号量用于进程间同步,若要在进程间传递数据需要结合共享内存。
  2. 信号量基于操作系统的 PV 操作,程序对信号量的操作都是原子操作。
  3. 每次对信号量的 PV 操作不仅限于对信号量值加 1 或减 1,而且可以加减任意正整数。
  4. 支持信号量组。

原子操作:就是在执行某一操作时不被打断。
linux原子操作问题来源于中断、进程的抢占以及多核smp系统中程序的并发执行。

2、原型

最简单的信号量是只能取 0 和 1 的变量,这也是信号量最常见的一种形式,叫做二值信号量(Binary Semaphore)。而可以取多个正整数的信号量被称为通用信号量。

Linux 下的信号量函数都是在通用的信号量数组上进行操作,而不是在一个单一的二值信号量上进行操作。

  1. 1 #include <sys/sem.h>
  2. // 创建或获取一个信号量组:若成功返回信号量集ID,失败返回-1
  3. 2 int semget(key_t key, int num_sems, int sem_flags); 创建信号量
  4. 参数1 :key
  5. 参数2: 信号量集当中的信号量个数 (1
  6. 参数3: (创建/获取) IPC_CREAT|0666
  7. 返回值:集合id
  8. // 对信号量组进行操作,改变信号量的值:成功返回0,失败返回-1
  9. 3 int semop(int semid, struct sembuf semoparray[], size_t numops);
  10. 参数1:semid
  11. 参数2: 次参数的数组可以在结构体进行
  12. 参数3: SEM_UNDO (默认)t
  13. void getkey(int id){
  14. struct sembuf set;
  15. set.sem_num =0; /* Operate on semaphore 0 */
  16. set.sem_op =-1; / * Wait for value to equal 0 */
  17. set.sem_flg = SEM_UNDO;
  18. semop(id,&set,1);
  19. printf("get the key\n");
  20. }
  21. void backkey(int id){
  22. struct sembuf set;
  23. set.sem_num =0; /* Operate on semaphore 0 */
  24. set.sem_op =1; /* Wait for value to equal 0 */
  25. set.sem_flg = SEM_UNDO;
  26. semop(id,&set,1);
  27. printf("back the key\n");
  28. }
  29. // 控制信号量的相关信息
  30. 4 int semctl(int semid, int sem_num, int cmd, ...); 初始化信号量
  31. 参数1:返回值信号量集合id
  32. 参数2:操作第几个信号量
  33. 参数3:(设置信号量的值)SETVAL
  34. 参数4: 一个结构体 (结构体的第一个数据提前初始化)

先实现一段代码 

  1. union semun {
  2. int val; /* Value for SETVAL */
  3. struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
  4. unsigned short *array; /* Array for GETALL, SETALL */
  5. struct seminfo *__buf; /* Buffer for IPC_INFO
  6. (Linux-specific) */
  7. };
  8. void getkey(int id){
  9. struct sembuf set;
  10. set.sem_num =0; /* Operate on semaphore 0 */
  11. set.sem_op =-1; /* Wait for value to equal 0 */
  12. set.sem_flg = SEM_UNDO;
  13. semop(id,&set,1);
  14. printf("get the key\n");
  15. }
  16. void backkey(int id){
  17. struct sembuf set;
  18. set.sem_num =0; /* Operate on semaphore 0 */
  19. set.sem_op =-1; /* Wait for value to equal 0 */
  20. set.sem_flg = SEM_UNDO;
  21. semop(id,&set,1);
  22. printf("get the key\n");
  23. }
  24. void backkey(int id){
  25. struct sembuf set;
  26. set.sem_num =0; /* Operate on semaphore 0 */
  27. set.sem_op =1; /* Wait for value to equal 0 */
  28. set.sem_flg = SEM_UNDO;
  29. semop(id,&set,1);
  30. printf("back the key\n");
  31. }
  32. int main(){
  33. union semun data;
  34. key_t key;
  35. key=ftok(".",'1');
  36. int semid =semget(key,1,IPC_CREAT|0666); //创建
  37. data.val=0; //这个值关乎信息量钥匙的有与没,拿与放
  38. semctl(semid, 0, SETVAL,data.val); //初始化 信息量
  39. pid_t pid=fork();
  40. if(pid>0){
  41. getkey(semid); //获取钥匙
  42. printf("the is father\n");
  43. backkey(semid); //退出钥匙
  44. }
  45. else if (pid==0){
  46. // getkey(semid);
  47. printf("the is chill\n");
  48. backkey(semid);
  49. }
  50. else{
  51. printf(" open pid error\n");
  52. }
  53. return 0;
  54. }

运行

  1. CLC@Embed_Learn:~/ccc$ ./sig
  2. the is chill
  3. back the key
  4. get the key
  5. the is father
  6. back the key
  7. CLC@Embed_Learn:~/ccc$ vi demo17.c

上面的例子如果不加信号量,则子进程会先执行完毕。这里加了信号量让子进程等待父进程执行完以后再执行。

更详细的代码参考

进程间通信(IPC)介绍_Heavy sea的博客-CSDN博客_进程ipc

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/爱喝兽奶帝天荒/article/detail/959515
推荐阅读
相关标签
  

闽ICP备14008679号