Posix信号量分为有名信号量和无名信号量

1. Posix有名信号量

有名信号量既可以用于线程间的同步也可以用于进程间的同步

sem都是创建在/dev/shm目录下,名字格式sem.xxx,只需要指定一个name名字即可。这是为什么名字被限制在NAME_MAX-4

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

创建并初始化有名信号灯

参数

name:信号灯的外部名字

oflag:选择创建或打开一个现有的信号灯

mode:权限位

value:信号灯初始值

返回值

成功时返回指向信号灯的指针,出错时为SEM_FAILED

oflag参数可以是0、O_CREAT(创建一个信号灯)或O_CREAT|O_EXCL(如果没有指定的信号灯就创建),如果指定了O_CREAT,那么第三个和第四个参数是需要的;该初始不能超过SEM_VALUE_MAX,这个常值必须低于为32767。二值信号灯的初始值通常为1,计数信号灯的初始值则往往大于1

如果指定了O_CREAT(而没有指定O_EXCL),那么只有所需的信号灯尚未存在时才初始化它。所需信号灯已存在条件下指定O_CREAT不是一个错误。该标志的意思仅仅是“如果所需信号灯尚未存在,那就创建并初始化它”。但是所需信号灯等已存在条件下指定O_CREAT|O_EXCL却是一个错误

  1. int sem_unlink(const char *name);

要等到所有打开该信号量的进程关闭该信号量后才删除该信号

2. 举例

  1. sem_t *sem;
  2. //创建信号量,返回sem_t类型指针
  3. if((sem = sem_open(argv[1],O_RDWR | O_CREAT,0644,atoi(optarg))) == SEM_FAILED)
  4. {
  5. perror("sem_open() error");
  6. exit(-1);
  7. }
  8. //关闭打开的信号量
  9. sem_close(sem);
  10. sem_unlink(argv[1]);

3. Posix无名信号量

基于内存的信号量

  1. int sem_init(sem_t *sem, int pshared, unsigned int value);

pshared:信号量是由进程内线程共享,还是由进程之间共享

value:信号量的初始值

如果 pshared 的值为 0,那么信号量将被进程内的线程共享,并且应该放置在这个进程的所有线程都可见的地址上(如全局变量,或者堆上动态分配的变量);如果 pshared 是非零值,那么信号量将在进程之间共享

  1. int sem_destroy(sem_t *sem);

销毁一个有其它线程或进程当前阻塞的信号量将导致未定义行为

使用一个已经销毁的信号量将导致未定义结果

  1. int sem_post(sem_t *sem);

sem_post函数的作用是给信号量的值加上一个“1”,它是一个“原子操作”,即同时对同一个信号量做加“1”操作的两个线程是不会冲突的

  1. int sem_wait(sem_t *sem);
  2. int sem_trywait(sem_t *sem);
  3. int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);

sem_wait函数也是一个原子操作,它的作用是从信号量的值减去一个“1”,但它永远会先等待该信号量为一个非零值才开始做减法

sem_trywait()是函数sem_wait的非阻塞版,它直接将信号量sem减1,同时返回错误代码

  1. int sem_getvalue(sem_t *sem, int *sval);

sem 指向的信号量当前值放置在 sval 指向的整数上

注:信号量的值可能在 sem_getvalue() 返回时已经被更改

4. 举例

建两个线程,这两个线程各自将自己的一个整型变量i从1 递增到100,并通过信号量控制递增的过程,即这两个整型变量的差不能超过5

  1. void* th_fn1(void* arg)
  2. {
  3. int i;
  4. for(i = 0; i < 100; ++i)
  5. {
  6. sem_wait(&sem1);
  7. printf("number in thread1 is %d\n",i);
  8. sem_post(&sem2);
  9. }
  10. pthread_exit((void*)"thread1exit\n");
  11. }
  12. void* th_fn2(void* arg)
  13. {
  14. int i;
  15. for(i = 0; i < 100; ++i)
  16. {
  17. sem_wait(&sem2);
  18. printf("number in thread2 is %d\n",i);
  19. sem_post(&sem1);
  20. }
  21. pthread_exit((void*)"thread2exit\n");
  22. }
  23. int main(void)
  24. {
  25. void *tret;
  26. sem_init(&sem1,0,5);
  27. sem_init(&sem2,0,5);
  28. pthread_t tid1,tid2;
  29. pthread_create(&tid1,NULL,th_fn1,NULL);
  30. pthread_create(&tid2,NULL,th_fn2,NULL);
  31. pthread_join(tid1,&tret);
  32. pthread_join(tid2,&tret);
  33. sem_destroy(&sem1);
  34. sem_destroy(&sem2);
  35. return 0;
  36. }

5. 互斥量和信号量的区别

互斥:是指某一资源同时只允许一个访问者对其进行访问,具有唯一性和排它性。但互斥无法限制访问者对资源的访问顺序,即访问是无序的

同步:是指在互斥的基础上,通过其它机制实现访问者对资源的有序访问

信号量(Posix)的更多相关文章

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

    Posix信号量 Posix 信号量 有名信号量 无名信号量 sem_open sem_init sem_close sem_destroy sem_unlink sem_wait sem_post ...

  2. Linux 信号量之Posix基于内存的信号量

    信号量(semaphore),也和互斥锁一样提供了线程间或者进程间的同步功能. 信号量有三种: Posix有名字的信号量 Posix基于内存的信号量 System V信号量 信号量比互斥锁高级,互斥锁 ...

  3. Linux 信号量之Posix有名字的信号量

    信号量(semaphore),也和互斥锁一样提供了线程间或者进程间的同步功能. 信号量有三种: Posix有名字的信号量 Posix基于内存的信号量 System V信号量 信号量比互斥锁高级,互斥锁 ...

  4. 第二章:Posix IPC

    2.1:概述 以下三种类型的IPC合称为“Posix IPC”: Posix消息队列 Posix信号量 Posix共享内存区 Posix IPC在访问它们的函数和描述它们的信息上有一些类似点.本章讲述 ...

  5. 【转载】Linux的进程间通信-信号量

    原文:Linux的进程间通信-信号量 Linux的进程间通信-信号量 版权声明: 本文章内容在非商业使用前提下可无需授权任意转载.发布. 转载.发布请务必注明作者和其微博.微信公众号地址,以便读者询问 ...

  6. POSIX 进程间通信 (可移植操作系统接口)

    1.什么是POSIX标准 Portable Operating System Interface for Computing System. 他是一个针对操作系统(准确地说是针对类Unix操作系统)的 ...

  7. System IPC 与Posix IPC(semaphore信号灯)

    POSIX下IPC主要包括三种: posix message queue posix semaphores posix shared memory sysytem v IPC包括: system v ...

  8. IPC之信号量

    无名信号量 POSIX标准提出了有名信号量和无名信号量来同步进程和线程,而linux(2.6以前)只实现了无名信号量. sem_overview中有详细介绍:man 7 sem_overview. S ...

  9. Linux多线程编程-信号量

    在Linux中.信号量API有两组.一组是多进程编程中的System V IPC信号量.另外一组是我们要讨论的POSIX信号量. 这两组接口类似,但不保证互换.POSIX信号量函数都已sem_开头,并 ...

  10. linux内核信号量

    用户态的信号量: System V 信号量 Posix 信号量 信号量是用于保护临界区的一种常用方法.它的使用和自旋锁类似.相同的是,只有得到信号量的进程才能执行临界区代码:不同的是,当获取不到信号量 ...

随机推荐

  1. liteos 异常接管(十五)

    1 概述 1.1 基本概念 异常接管是操作系统对在运行期间发生异常的情况进行处理的一系列动作,譬如打印异常发生时当前函数调用栈信息. cpu现场信息.任务的堆栈情况等. 异常接管作为一种调测手段,可以 ...

  2. layui获取checkbox复选框值

    获取layui表单复选框已选中的数据 HTML <!DOCTYPE html> <html> <head> <meta charset="utf-8 ...

  3. appium---元素定位方法

    在我们做自动化测试的过程中,最基本的就是要会元素定位,也是自动化中的灵魂所在,如果一个自动化测试工程师说不会定位元素定位,那么肯定也不会做自动化了. 如何查看元素 小伙伴们都知道如果是web端可以通过 ...

  4. spark-shell 中rdd常用方法

    centos 7.2     spark 2.3.3      scala 2.11.11    java 1.8.0_202-ea spark-shell中为scala语法格式 1.distinct ...

  5. nginx 图片访问404 (使用location中使用 root,alias的区别)

    问题描述: 在/data/code_img/文件下有很多验证码图片,想将他们展示出来 希望通过 http://127.0.0.1/img/1.png 这种形式访问到对应图片,刚开始nginx中配置如下 ...

  6. 关于yyyy-MM-dd格式日期字符串,解析成LocalDateTime遇到的问题

    yyyy-MM-dd -> LocalDateTime 直接把yyyy-MM-dd格式的日期字符串解析成LocalDateTime会抛出异常 try { LocalDateTime localD ...

  7. 非阻塞式I/O

    套接字的默认状态是阻塞的.这就意味着当发出一个不能立即完成的套接字调用时,其进程将被投入睡眠,等待相应的操作完成.可能阻塞的套接字调用可分为以下4类 (1)输入操作,包括read,readv,recv ...

  8. day80_10_29git冲突解决与短信服务redis

    一.开发中的操作. 在项目开发中,在工作区进行开发,开发结束后提交到本地版本库. 再拉取远程仓库,具体如下: """ 1.开发前,拉一次远程仓库 2.工作区进行开发 3. ...

  9. Bliss OS 12.1下载 PC上Android10体验

    下载也不是一帆风顺啊 这是设计者的secret: https://forum.xda-developers.com/android/software/bliss-os-x86-pc-s-12-x-de ...

  10. Spring Cloud Alibaba Sentinel对Feign的支持

    Spring Cloud Alibaba Sentinel 除了对 RestTemplate 做了支持,同样对于 Feign 也做了支持,如果我们要从 Hystrix 切换到 Sentinel 是非常 ...