linux POSIX 信号量介绍
信号量
一.什么是信号量
信号量的使用主要是用来保护共享资源,使得资源在一个时刻只有一个进程(线程)使用。
多线程可以同时运行多个线程函数完成功能,但是对于共享数据如果不加以锁定,随意改变共享数据的值会发生期望之外的结果!
本文主要介绍Linux下的 POSIX信号量:有名信号量和无名信号量
有名信号量,其值保存在文件中, 所以它可以用于线程也可以用于进程间的同步;
无名信号量,其值保存在内存中,故只用于线程的同步,多用共享内存。
POSIX信号量包含一个非负整型变量,并且带有两个原子操作wait 和signal。wait 还可以被称为down、P 或lock,signal 还可以被称为up、V、unlock 或post。在Uinx的API中用的是wait和post。
如果信号量的非负整形变量S大于零,wait就将其减1,如果S 等于0,wait 就将调用线程阻塞。对于post 操作,如果有线程在信号量上阻塞(此时S 等于0),signal就会解除对某个等待线程的阻塞,使其从wait 中返回,如果没有线程阻塞在信号量上,post 就将S加1。
简单来说即:当S大于0时,线程正常运行不会阻塞;当S=0时,线程阻塞直到有post操作将其+1。假设S值设为1,信号量可实现互斥的功能。
信号量的一般操作是 创建-->PV操作-->删除
二. 无名信号量
头文件: <semaphore.h>
int sem_init(sem_t *sem, int pshared,unsigned value);
功能:初始化指定的信号量
返回值:成功 0 ; 错误 错误号。
参数说明:sem:信号量变量名;参数value为信号量的初始值。
参数pshared用于说明信号量的共享范围,如果pshared为0,那么该信号量只能由初始化这个信号量的进程中的线程使用,如果pshared非零,任何可以访问到这个信号量的进程都可以使用这个信号量。
必须保证只调用sem_init()进行初始化一次,对于一个已初始化过的信号量调用sem_init()的行为是未定义的
int sem_destroy(sem_t *sem);
功能:销毁一个指定的信号量
返回值:成功 0 ; 错误 错误号。
参数说明:sem:信号量变量名(sem_init内值)
摧毁一个有线程阻塞在其上的信号量的行为是未定义的。
P操作:
int sem_trywait(sem_t *sem);
int sem_wait(sem_t *sem);
int sem_timedwait(sem_t * sem, const struct timespec time);
减1信号量的值。信号量值为0时,sem_wait会阻塞,直到成功使信号量减1或者被信号中断时才返回;
sem_trywait为非阻塞版本,当信号量为0时,该函数返回-1并且将errno置为EAGAIN
sem_timedwait带有超时功能,超时到期并且信号量计数没能减1,sem_timedwait将返回-1且将errno设置为ETIMEDOUT。(毕竟一直阻塞也不是办法。。)
V操作:
int sem_post(sem_t *sem);
信号量加1,若此时有sem_wait正在阻塞则唤醒执行。
取值操作:
int sem_t getvalue(sem_t sem, int *val);
获取信号量的值,一般只用来调试,打印val查看。
三. 有名信号量
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参数可以为:0,O_CREAT,O_EXCL。如果为0表示打开一个已存在的信号量,如果为O_CREAT,表示如果信号量不存在就创建一个信号量,如果存在则打开被返回。此时mode和value需要指定。如果为O_CREAT | O_EXCL,表示如果信号量已存在会返回错误。
mode参数用于创建信号量时,表示信号量的权限位,和open函数一样包括:S_IRUSR,S_IWUSR,S_IRGRP,S_IWGRP,S_IROTH,S_IWOTH。
int sem_close(sem_t *sem);
功能:sem_close用于关闭打开的信号量。当一个进程终止时,内核对其上仍然打开的所有有名信号量自动执行这个操作。
返回值:成功返回0,失败返回-1
调用sem_close关闭信号量并没有把它从系统中删除它,POSIX有名信号量是随内核持续的。即使当前没有进程打开某个信号量它的值依然保持。直到内核重新自举或调用sem_unlink()删除该信号量。
int sem_unlink(const char *name);
功能:将有名信号量立刻从系统中删除,但信号量的销毁是在所有进程都关闭信号量的时候(只close是不够的!)
返回值:成功返回0,失败返回-1
有名信号量的PV操作与无名信号量类似。
参考网上代码,自测了使用信号量同步线程的功能:
sem_t sem_g, sem_p;
int g_i_res=; void *pid_g(void)
{
while()
{
sem_wait(&sem_g);
g_i_res++;
Sleep();
if(g_i_res>)
system("pause");
sem_post(&sem_p);
} } void *pid_p(void)
{
while()
{
sem_wait(&sem_p);
printf("%d ", g_i_res);
fflush(stdout);
sem_post(&sem_g); } } int main()
{ pthread_t tid1, tid2;
sem_init(&sem_g, , );
sem_init(&sem_p, , ); pthread_create(&tid1, NULL, pid_g, NULL);
pthread_create(&tid2, NULL, pid_p, NULL); pthread_join(tid1, NULL);
pthread_join(tid2, NULL); return ;
}
说明:头文件按需添加,一般有<pthread.h> <semaphore.h> ,由于虽然是gcc编译但在Windows环境,所以用了<windows.h>的Sleep()

自己运行可以看到数字依次递增的打印过程,若不加system(pause)会无限刷屏的。。。
遇到新内容再更新吧~
linux POSIX 信号量介绍的更多相关文章
- linux Posix 信号量 一
信号量是一种用于提供不同进程间或一个给定进程的不同线程间同步手段的原语. linux提供两种信号量,“内核信号量”和“用户态进程信号量”,“用户态信号量”又分为“Posix”,“System V”信号 ...
- linux Posix 信号量 二
一.Posix信号量 1.Posix信号量分为两种: 1. 有名信号量:使用Posix IPC名字标识(有名信号量总是既可用于线程间的同步,又可以用于进程间的同步) 2. 内存信号量:存放在共 ...
- linux POSIX信号量
POSIX信号量机制是3种IPC机制之一,3种IPC机制源于POSIX.1的实时扩展. 创建一个新的命名信号量或者使用一个现有信号量 #include <fcntl.h> #include ...
- linux Posix 信号量 三 (经典例子)
本文将阐述一下信号量的作用及经典例子,当中包括“<越狱>寄信”,“家庭吃水果”,“五子棋”,“接力赛跑”,“读者写者”,“四方恋爱”等 首先,讲 semWait操作(P操作)和semSig ...
- Linux进程间通信IPC学习笔记之同步二(Posix 信号量)
Linux进程间通信IPC学习笔记之同步二(Posix 信号量)
- Linux进程同步之POSIX信号量
POSIX信号量是属于POSIX标准系统接口定义的实时扩展部分.在SUS(Single UNIX Specification)单一规范中,定义的XSI IPC中也同样定义了人们通常称为System V ...
- Linux多线程实践(5) --Posix信号量与互斥量解决生产者消费者问题
Posix信号量 Posix 信号量 有名信号量 无名信号量 sem_open sem_init sem_close sem_destroy sem_unlink sem_wait sem_post ...
- linux c编程:Posix信号量
POSIX信号量接口,意在解决XSI信号量接口的几个不足之处: POSIX信号量接口相比于XSI信号量接口,允许更高性能的实现. POSIX信号量接口简单易用:没有信号量集,其中一些接口模仿了我们熟悉 ...
- linux网络编程之posix信号量与互斥锁
继上次学习了posix线程之后,这次来讨论一下posix信号量与互斥锁相关的知识: 跟posix消息队列,共享内存的打开,关闭,删除操作一样,不过,上面的函数是对有名信号量进行操作,通过man帮助可以 ...
随机推荐
- 关于mysql数据库优化
关于mysql数据库优化 以我之愚见,数据库的优化在于优化存储和查询速度 目前主要的优化我认为是优化查询速度,查询速度快了,提高了用户的体验 我认为优化主要从两方面进行考虑, 优化数据库对象, 优化s ...
- Overload和Override的区别 C++ Java
Overload:顾名思义,就是Over(重新)——load(加载),所以中文名称是重载. 它可以表现类的多态性,可以是函数里面可以有相同的函数名但是参数名.返回值.类型不能相同: 或者说可以改变参数 ...
- python---redis缓存页面实现
import tornado.web from controllers.BaseController import BaseRequestHandler import redis pool = red ...
- python---RabbitMQ(2)exchange中订阅者模式fanout<广播>,(一对多,发布一条消息,多人同时接收)
fanout:广播:所有bind到此exchange的queue都可以接受到消息 生产者: # coding:utf8 # __author: Administrator # date: // # / ...
- Hadoop记录-MRv2(Yarn)运行机制
1.MRv2结构—Yarn模式运行机制 Client---客户端提交任务 ResourceManager---资源管理 ---Scheduler调度器-资源分配Containers ----在Yarn ...
- 关于js事件执行顺序小技巧
js事件执行顺序是js中一个老生常谈的一个话题, 聊这个话题之前我们先谈谈怎么给页面元素绑定我们需要的事件 1.给页面元素绑定事件 a)直接在元素上面加上需要绑定的事件,如 <button ty ...
- GUI之ScrollView的使用
ScrollView ScrollView是unity提供的一个方便的滚动视图. 组成 ScrollView由四个部分组成: ViewPort 和 Content ScrollView: 视图范围,C ...
- Winform程序双向绑定
程序比较简单,一看就明白,主要需要实现INotifyPropertyChanged using System; using System.Collections.Generic; using Syst ...
- Android studio 自动导入(全部)包 import
http://blog.csdn.net/buaaroid/article/details/44979629 1 Android studio 只有import单个包的快捷键:Alt+Enter.没有 ...
- Regex实例
using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...