信号量(Posix)
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)的更多相关文章
- Linux多线程实践(5) --Posix信号量与互斥量解决生产者消费者问题
Posix信号量 Posix 信号量 有名信号量 无名信号量 sem_open sem_init sem_close sem_destroy sem_unlink sem_wait sem_post ...
- Linux 信号量之Posix基于内存的信号量
信号量(semaphore),也和互斥锁一样提供了线程间或者进程间的同步功能. 信号量有三种: Posix有名字的信号量 Posix基于内存的信号量 System V信号量 信号量比互斥锁高级,互斥锁 ...
- Linux 信号量之Posix有名字的信号量
信号量(semaphore),也和互斥锁一样提供了线程间或者进程间的同步功能. 信号量有三种: Posix有名字的信号量 Posix基于内存的信号量 System V信号量 信号量比互斥锁高级,互斥锁 ...
- 第二章:Posix IPC
2.1:概述 以下三种类型的IPC合称为“Posix IPC”: Posix消息队列 Posix信号量 Posix共享内存区 Posix IPC在访问它们的函数和描述它们的信息上有一些类似点.本章讲述 ...
- 【转载】Linux的进程间通信-信号量
原文:Linux的进程间通信-信号量 Linux的进程间通信-信号量 版权声明: 本文章内容在非商业使用前提下可无需授权任意转载.发布. 转载.发布请务必注明作者和其微博.微信公众号地址,以便读者询问 ...
- POSIX 进程间通信 (可移植操作系统接口)
1.什么是POSIX标准 Portable Operating System Interface for Computing System. 他是一个针对操作系统(准确地说是针对类Unix操作系统)的 ...
- System IPC 与Posix IPC(semaphore信号灯)
POSIX下IPC主要包括三种: posix message queue posix semaphores posix shared memory sysytem v IPC包括: system v ...
- IPC之信号量
无名信号量 POSIX标准提出了有名信号量和无名信号量来同步进程和线程,而linux(2.6以前)只实现了无名信号量. sem_overview中有详细介绍:man 7 sem_overview. S ...
- Linux多线程编程-信号量
在Linux中.信号量API有两组.一组是多进程编程中的System V IPC信号量.另外一组是我们要讨论的POSIX信号量. 这两组接口类似,但不保证互换.POSIX信号量函数都已sem_开头,并 ...
- linux内核信号量
用户态的信号量: System V 信号量 Posix 信号量 信号量是用于保护临界区的一种常用方法.它的使用和自旋锁类似.相同的是,只有得到信号量的进程才能执行临界区代码:不同的是,当获取不到信号量 ...
随机推荐
- 版本管理·玩转git(团队合作)
如果你想让一位叫"伙夫"的程序员,和你一起开发,首先你得在你的代码仓库把伙夫添加到此项目中来,让其成为开发者. 具体步骤: 项目->管理->项目成员管理->开发者 ...
- Python的lambda表达式、filter、map、reduce等函数的用法
lambda是表达式,用于创建匿名函数,可以和filter.map.reduce配合使用.本文环境Python3.7. 一.lambda表达式 lambda 只包含一个语句,用于创建匿名函数. 语法: ...
- MSSQL 插入数据时候,如果存在则更新的方法分享
摘要:下文讲述MSSQL中,插入数据时,如果存在则更新,否则就插入数据的方法分享实验环境:sql server 2017 mssql中,我们可以采用 MERGE INTO 关键字实现此功能,当两者匹配 ...
- 前端基础之BOM和DOM操作
目录 BOM和DOM定义 windows对象 windows的子对象 navigator对象 screen对象 history对象 location对象 弹出框 警告框 确认框 提示框 计时相关 se ...
- Oracle 导入dmp 故障存储文件
创建表空间及用户CREATE TABLESPACE OracleDBFDATAFILE 'D:\app\zhoulx\oradata\bdc\OracleDBF.DBF' SIZE 100M AUTO ...
- leetcode 分类
https://www.douban.com/note/330562764/ https://blog.csdn.net/Irving_zhang/article/details/78835035 h ...
- java中的转义字符(遇到再进一步总结)
一.常见的转义字符转移字符对应的英文是escape character , 转义字符串(Escape Sequence)字母前面加上捺斜线""来表示常见的那些不能显示的ASCII字 ...
- SQL Server 修改数据库
1. 可视化界面修改数据库 (1)右击数据库,然后选择属性. (2)在工具选项卡中,选择[文件]页,可以更改所有者,文件大小,自增量等参数. 2. 使用ALTER Database修改数据库 (1) ...
- 【2019.8.12 慈溪模拟赛 T1】钥匙(key)(暴力DP)
暴力\(DP\) 这题做法很多,有\(O(n^2)\)的,有\(O(n^2logn)\)的,还有徐教练的\(O(nlogn)\)的,甚至还有\(bzt\)的二分+线段树优化建图的费用流. 我懒了点,反 ...
- 【2019.7.22 NOIP模拟赛 T1】麦克斯韦妖(demon)(质因数分解+DP)
暴力\(DP\) 先考虑暴力\(DP\)该怎么写. 因为每个序列之后是否能加上新的节点只与其结尾有关,因此我们设\(f_i\)为以\(i\)为结尾的最长序列长度. 每次枚举一个前置状态,判断是否合法之 ...