进程同步与相互排斥:POSIX有名信号量

在 POSIX 标准中,信号量分两种,一种是无名信号量,一种是有名信号量。

无名信号量一般用于线程间同步或相互排斥,而有名信号量一般用于进程间同步或相互排斥

它们的差别和管道及命名管道的差别类似。无名信号量则直接保存在内存中,而有名信号量要求创建一个文件。前面我们学习了无名信号量的使用(详情请看《无名信号量》)。这里我们学习有名信号量的使用。

1)创建一个有名信号量

所需头文件:

#include <fcntl.h>

#include <sys/stat.h>

#include <semaphore.h>

当有名信号量存在时使用:

sem_t *sem_open(const char *name, int oflag);

当有名信号量不存在时使用:

sem_t *sem_open(const char *name, int oflag, mode_t mode, unsigned int value);

功能:

创建一个有名信号量。

參数:

name:信号量文件名称。注意,不能指定路径名。由于有名信号量,默认放在/dev/shm 里。例如以下图:

flags:sem_open() 函数的行为标志。

mode:文件权限(可读、可写、可运行)的设置。

value:信号量初始值。

返回值:

成功:信号量的地址

失败:SEM_FAILED

2)关闭有名信号量

所需头文件:

#include <semaphore.h>

int sem_close(sem_t *sem);

功能:

关闭有名信号量。

參数:

sem:指向信号量的指针。

返回值:

成功:0

失败:-1

3)删除有名信号量文件

所需头文件:

#include <semaphore.h>

int sem_unlink(const char *name);

功能:

删除有名信号量的文件。

參数:

name:有名信号量文件名称。

返回值:

成功:0

失败:-1

4)信号量 PV 操作

使用方法和《POSIX 无名信号量》一样,详情请点此链接。

有名信号量实现进程间相互排斥功能:

[cpp] view
plain
copy

  1. #include<stdio.h>
  2. #include<semaphore.h>
  3. #include<fcntl.h>
  4. #include<unistd.h>
  5. #include<sys/stat.h>
  6. #include<sys/types.h>
  7. void printer(sem_t *sem, char *str)
  8. {
  9. sem_wait(sem);  //信号量减一
  10. while(*str!=‘\0‘)
  11. {
  12. putchar(*str);
  13. fflush(stdout);
  14. str++;
  15. sleep(1);
  16. }
  17. printf("\n");
  18. sem_post(sem);  //信号量加一
  19. }
  20. int main(int argc, char *argv[])
  21. {
  22. pid_t pid;
  23. sem_t *sem = NULL;
  24. pid = fork(); //创建进程
  25. if(pid<0){ //出错
  26. perror("fork error");
  27. }else if(pid == 0){ //子进程
  28. //跟open()打开方式非常相似,不同进程仅仅要名字一样。那么打开的就是同一个有名信号量
  29. sem = sem_open("name_sem", O_CREAT|O_RDWR, 0666, 1); //信号量值为 1
  30. if(sem == SEM_FAILED){ //有名信号量创建失败
  31. perror("sem_open");
  32. return -1;
  33. }
  34. char *str1 = "hello";
  35. printer(sem, str1); //打印
  36. sem_close(sem); //关闭有名信号量
  37. _exit(1);
  38. }else if(pid > 0){ //父进程
  39. //跟open()打开方式非常相似,不同进程仅仅要名字一样,那么打开的就是同一个有名信号量
  40. sem = sem_open("name_sem", O_CREAT|O_RDWR, 0666, 1); //信号量值为 1
  41. if(sem == SEM_FAILED){//有名信号量创建失败
  42. perror("sem_open");
  43. return -1;
  44. }
  45. char *str2 = "world";
  46. printer(sem, str2); //打印
  47. sem_close(sem); //关闭有名信号量
  48. wait(pid, NULL); //等待子进程结束
  49. }
  50. sem_unlink("name_sem");//删除有名信号量
  51. return 0;
  52. }

执行结果例如以下:

有名信号量实现进程间同步功能(print2 先打印。再到 print1 打印):

print1.c 代码例如以下:

[cpp] view
plain
copy

  1. #include <fcntl.h>           /* For O_* constants */
  2. #include <sys/stat.h>        /* For mode constants */
  3. #include <semaphore.h>
  4. #include <stdio.h>
  5. void print(sem_t *print1, sem_t *print2)
  6. {
  7. int i = 0;
  8. while(1)
  9. {
  10. sem_wait(print1);
  11. i++;
  12. printf("int print1 i = %d\n", i);
  13. sem_post(print2);
  14. }
  15. }
  16. int main(int argc, char **argv)
  17. {
  18. sem_t *print1, *print2;
  19. print1 = sem_open("sem_print1", O_CREAT, 0777, 0);
  20. if(SEM_FAILED == print1)
  21. {
  22. perror("sem_open");
  23. }
  24. print2 = sem_open("sem_print2", O_CREAT, 0777, 1);
  25. if(SEM_FAILED == print2)
  26. {
  27. perror("sem_open");
  28. }
  29. print(print1, print2);
  30. return 0;
  31. }

print2.c 代码例如以下:

[cpp] view
plain
copy

  1. #include <fcntl.h>           /* For O_* constants */
  2. #include <sys/stat.h>        /* For mode constants */
  3. #include <semaphore.h>
  4. #include <stdio.h>
  5. void print(sem_t *print1, sem_t *print2)
  6. {
  7. int i = 0;
  8. while(1)
  9. {
  10. sem_wait(print2);
  11. i++;
  12. printf("in print2 i = %d\n", i);
  13. sleep(1);
  14. sem_post(print1);
  15. }
  16. }
  17. int main(int argc, char **argv)
  18. {
  19. sem_t *print1, *print2;
  20. print1 = sem_open("sem_print1", O_CREAT, 0777, 0);
  21. if(SEM_FAILED == print1)
  22. {
  23. perror("sem_open");
  24. }
  25. print2 = sem_open("sem_print2", O_CREAT, 0777, 1);
  26. if(SEM_FAILED == print2)
  27. {
  28. perror("sem_open");
  29. }
  30. print(print1, print2);
  31. return 0;
  32. }

删除有名信号量演示样例代码例如以下:

[cpp] view
plain
copy

  1. #include <semaphore.h>
  2. #include <stdio.h>
  3. void sem_del(char *name)
  4. {
  5. int ret;
  6. ret = sem_unlink(name);
  7. if(ret < 0)
  8. {
  9. perror("sem_unlink");
  10. }
  11. }
  12. int main(int argc, char **argv)
  13. {
  14. sem_del("sem_print1"); //删除信号量文件sem_print1
  15. sem_del("sem_print2"); //删除信号量文件sem_print2
  16. return 0;
  17. }

makefile 代码例如以下:

[plain] view
plain
copy

  1. all:
  2. gcc sem_del.c -o sem_del -lpthread
  3. gcc print1.c -o print1 -lpthread
  4. gcc print2.c -o print2 -lpthread
  5. clean:
  6. rm sem_del print1 print2

执行程序时。先把有名信号量删除(sem_del)。再分别执行 print1 和 print2:

本教程演示样例代码下载请点此处。

转自:http://blog.csdn.net/tennysonsky/article/details/46500417

时间: 2024-12-15 21:22:20

进程同步与相互排斥:POSIX有名信号量的相关文章

Linux系统编程——进程同步与互斥:POSIX有名信号量

在 POSIX 标准中,信号量分两种,一种是无名信号量,一种是有名信号量.无名信号量一般用于线程间同步或互斥,而有名信号量一般用于进程间同步或互斥.它们的区别和管道及命名管道的区别类似,无名信号量则直接保存在内存中,而有名信号量要求创建一个文件.前面我们学习了无名信号量的使用(详情请看<无名信号量>),这里我们学习有名信号量的使用. 1)创建一个有名信号量 所需头文件: #include <fcntl.h> #include <sys/stat.h> #include

进程同步与互斥:POSIX有名信号量

在 POSIX 标准中,信号量分两种,一种是无名信号量,一种是有名信号量.无名信号量一般用于线程间同步或互斥,而有名信号量一般用于进程间同步或互斥.它们的区别和管道及命名管道的区别类似,无名信号量则直接保存在内存中,而有名信号量要求创建一个文件.前面我们学习了无名信号量的使用(详情请看<无名信号量>),这里我们学习有名信号量的使用. 1)创建一个有名信号量 所需头文件: #include <fcntl.h> #include <sys/stat.h> #include

一起talk C栗子吧(第一百回:C语言实例--使用信号量进行进程间同步与相互排斥一)

各位看官们.大家好,上一回中咱们说的是进程间同步与相互排斥的样例,这一回咱们说的样例是:使用信号量进行进程间同步与相互排斥. 闲话休提,言归正转.让我们一起talk C栗子吧! 看官们,信号量是由著名计算机科学家迪杰斯特拉(Dijkstra)提出的一种概念,专门用来解决进程间同步与相互排斥.在他提出的概念中信号量是一个非负整数值. 信号量的操作仅仅能有两种原子操作: 等待信号; 发送信号. "什么是原子操作呢?"台下有看官在提问.原子操作就是指某个动作在运行时不能被其他动作中断,它会一

Linux相互排斥与同步应用(三):posix线程实现单个生产者和单个消费者模型

[版权声明:尊重原创.转载请保留出处:blog.csdn.net/shallnet 或 .../gentleliu.文章仅供学习交流,请勿用于商业用途] 在第一节说到了生产者消费者问题,这一节我们来实现这样一个稍作改动的模型: 初始时缓冲区为空.生产者向缓冲区写入数据.消费者在缓冲区为空的情况下睡眠,当生产者写满缓冲区一半之后后通知消费者能够開始消费.生产者開始睡眠.直到消费者消费完缓冲区一半后通知生产者能够開始生产为止,当中生产者和消费者对缓冲区的訪问时相互排斥的. 以下来看一下实现: #in

Linux同步与相互排斥应用(零):基础概念

[版权声明:尊重原创,转载请保留出处:blog.csdn.net/shallnet 或 .../gentleliu,文章仅供学习交流,请勿用于商业用途] 当操作系统进入多道批处理系统时代以后.一个系统中就存在多个任务,每一个任务都依照一定的算法进行调度来使用内存.cpu等共享资源. 当当中一个任务等待其它资源时,该任务能够临时睡眠,操作系统调度另外任务继续运行额,这样能够使系统资源得到最大化利用.而无需像曾经单道批处理系统那样仅仅有当一个任务完毕之后才运行下一个任务. 可是由此也引入了多任务并发

RAII手法封装相互排斥锁

CriticalSectionWrapper是一个接口类 class CriticalSectionWrapper { public: // Factory method, constructor disabled static CriticalSectionWrapper* CreateCriticalSection(); virtual ~CriticalSectionWrapper() {} // Tries to grab lock, beginning of a critical se

Linux多线程同步之相互排斥量和条件变量

1. 什么是相互排斥量 相互排斥量从本质上说是一把锁,在訪问共享资源前对相互排斥量进行加锁,在訪问完毕后释放相互排斥量上的锁. 对相互排斥量进行加锁以后,不论什么其它试图再次对相互排斥量加锁的线程将会被堵塞直到当前线程释放该相互排斥锁.假设释放相互排斥锁时有多个线程堵塞,所以在该相互排斥锁上的堵塞线程都会变成可进行状态.第一个变成执行状态的线程能够对相互排斥量加锁.其它线程在次被堵塞,等待下次执行状态. pthread_mutex_t 就是POSIX对于mutex的实现. 函数名 參数 说明 p

Linux 同步方法剖析--内核原子,自旋锁和相互排斥锁

在学习 Linux® 的过程中,您或许接触过并发(concurrency).临界段(critical section)和锁定,可是怎样在内核中使用这些概念呢?本文讨论了 2.6 版内核中可用的锁定机制,包含原子运算符(atomic operator).自旋锁(spinlock).读/写锁(reader/writer lock)和内核信号量(kernel semaphore). 本文还探讨了每种机制最适合应用到哪些地方.以构建安全高效的内核代码. 本文讨论了 Linux 内核中可用的大量同步或锁定

线程同步与互斥:POSIX无名信号量

信号量概述 信号量广泛用于进程或线程间的同步和互斥,信号量本质上是一个非负的整数计数器,它被用来控制对公共资源的访问. 编程时可根据操作信号量值的结果判断是否对公共资源具有访问的权限,当信号量值大于 0 时,则可以访问,否则将阻塞.PV 原语是对信号量的操作,一次 P 操作使信号量减1,一次 V 操作使信号量加1. 信号量主要用于进程或线程间的同步和互斥这两种典型情况. 信号量用于互斥: 信号量用于同步: 在 POSIX 标准中,信号量分两种,一种是无名信号量,一种是有名信号量.无名信号量一般用