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

1. Posix有名信号量

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

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

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:信号灯的外部名字

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却是一个错误

int sem_unlink(const char *name);

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

2. 举例

sem_t *sem;

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

3. Posix无名信号量

基于内存的信号量

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

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

value:信号量的初始值

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

int sem_destroy(sem_t *sem);

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

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

int sem_post(sem_t *sem);

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

int sem_wait(sem_t *sem);
int sem_trywait(sem_t *sem);
int sem_timedwait(sem_t *sem, const struct timespec *abs_timeout);

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

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

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

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

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

4. 举例

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

void* th_fn1(void* arg)
{
int i;
for(i = 0; i < 100; ++i)
{
sem_wait(&sem1);
printf("number in thread1 is %d\n",i);
sem_post(&sem2);
}
pthread_exit((void*)"thread1exit\n");
}
void* th_fn2(void* arg)
{
int i;
for(i = 0; i < 100; ++i)
{
sem_wait(&sem2);
printf("number in thread2 is %d\n",i);
sem_post(&sem1);
}
pthread_exit((void*)"thread2exit\n");
}
int main(void)
{
void *tret;
sem_init(&sem1,0,5);
sem_init(&sem2,0,5);
pthread_t tid1,tid2;
pthread_create(&tid1,NULL,th_fn1,NULL);
pthread_create(&tid2,NULL,th_fn2,NULL);
pthread_join(tid1,&tret);
pthread_join(tid2,&tret);
sem_destroy(&sem1);
sem_destroy(&sem2);
return 0;
}

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. 版本管理·玩转git(团队合作)

    如果你想让一位叫"伙夫"的程序员,和你一起开发,首先你得在你的代码仓库把伙夫添加到此项目中来,让其成为开发者. 具体步骤: 项目->管理->项目成员管理->开发者 ...

  2. Python的lambda表达式、filter、map、reduce等函数的用法

    lambda是表达式,用于创建匿名函数,可以和filter.map.reduce配合使用.本文环境Python3.7. 一.lambda表达式 lambda 只包含一个语句,用于创建匿名函数. 语法: ...

  3. MSSQL 插入数据时候,如果存在则更新的方法分享

    摘要:下文讲述MSSQL中,插入数据时,如果存在则更新,否则就插入数据的方法分享实验环境:sql server 2017 mssql中,我们可以采用 MERGE INTO 关键字实现此功能,当两者匹配 ...

  4. 前端基础之BOM和DOM操作

    目录 BOM和DOM定义 windows对象 windows的子对象 navigator对象 screen对象 history对象 location对象 弹出框 警告框 确认框 提示框 计时相关 se ...

  5. Oracle 导入dmp 故障存储文件

    创建表空间及用户CREATE TABLESPACE OracleDBFDATAFILE 'D:\app\zhoulx\oradata\bdc\OracleDBF.DBF' SIZE 100M AUTO ...

  6. leetcode 分类

    https://www.douban.com/note/330562764/ https://blog.csdn.net/Irving_zhang/article/details/78835035 h ...

  7. java中的转义字符(遇到再进一步总结)

    一.常见的转义字符转移字符对应的英文是escape character , 转义字符串(Escape Sequence)字母前面加上捺斜线""来表示常见的那些不能显示的ASCII字 ...

  8. SQL Server 修改数据库

    1. 可视化界面修改数据库 (1)右击数据库,然后选择属性. (2)在工具选项卡中,选择[文件]页,可以更改所有者,文件大小,自增量等参数. 2.  使用ALTER Database修改数据库 (1) ...

  9. 【2019.8.12 慈溪模拟赛 T1】钥匙(key)(暴力DP)

    暴力\(DP\) 这题做法很多,有\(O(n^2)\)的,有\(O(n^2logn)\)的,还有徐教练的\(O(nlogn)\)的,甚至还有\(bzt\)的二分+线段树优化建图的费用流. 我懒了点,反 ...

  10. 【2019.7.22 NOIP模拟赛 T1】麦克斯韦妖(demon)(质因数分解+DP)

    暴力\(DP\) 先考虑暴力\(DP\)该怎么写. 因为每个序列之后是否能加上新的节点只与其结尾有关,因此我们设\(f_i\)为以\(i\)为结尾的最长序列长度. 每次枚举一个前置状态,判断是否合法之 ...