Linux - 进程间通信 - 信号量
一、概念
简单来讲,信号量是一个用来描述临界资源的资源个数的计数器。
信号量的本质是一种数据操作锁,它本身不具有数据交换的功能,而是通过控制其他的通信资源(文件、外部设备等)来实现进程间通信,
他本身更只是一种外部资源的标识。信号量在此过程中负责数据操作的同步、互斥等功能。
当请求 一个使用信号量来表示 的资源时,进程需要先读取信号量的值来判断资源是否可用。大于0,资源可以请求;等于0,无资源可用,
进程会进入睡眠状态直至资源可用。
当进程不再使用一个使用信号量控制的共享资源时,信号量的值+1,对信号量的值进行的增减都是原子操作,这是由于信号量的主要作用
是维护资源的互斥或多进程的同步访问。而在信号量的创建及初始化上,不能保证操作均为原子性。
原子操作:
所谓原子操作是指不会被线程调度机制打断的操作;这种操作一旦开始,就一直运行到结束,中间不会有任何 context switch (切换到另
一个线程)。共享数据(全局变量或堆变量)的自增(++)操作在多线程环境下会出现错误是因为这个操作(一条c语句)被编译为汇编代码后不
止一条指令,因此在执行的时候可能执行了一半就被调度系统打断,去执行别的代码。
我们把单指令的操作称为原子的(Atomic),因为无论如何,单条指令的执行是不会被打断的。
总而言之,原子操作的状态是要么不做,要么做并且完成,没有做了但没有完成这种状态。
二、为什么要使用信号量
为了防止出现因多个程序同时访问一个共享资源而引发的一系列问题,我们需要一种方法,他可以通过生成并使用令牌来授权,在任意时刻只能
由一个执行线程访问代码的临界区域。临界区域是指执行数据更新的代码需要独占的执行。而信号量就可以提供这样的一 种访问机制让一个临界区
域同一时间只有一个线程访问它,也就是说信号量使用来协调进程对共享资源的访问的。其中共享内存的使用就要用到信号量。
三、信号量的工作原理:
我们这里讲的是二元信号量:
二元信号量(Binary Semaphore)是最简单的一种锁,它只用两种状态:占用与非占用。它适合只能被唯一一个线程访问的资源。当二元信号量
处于非占用状态时,第一个试图获取该二元信号量的线程会获得该锁,并将二元信号量置为占用状态,此后其他的所有试图获取该二元信号量的线程将会
等待,知道该锁被释放。
由于信号量只能进行两种操作:等待和发送信号,即 P(sv)和 V(sv)。它们的行为是这样的:
P(sv):若sv值大于0,就给它减1,;若他的值为0,就挂起该进程的执行
V(sv)如果有其他进程因等待sv而被挂起,就让他恢复运行;如果没有进程因等待而被挂起,那就给他们加1。
举个例子:
就是两个进程共享信号量sv,一旦其中一个进程执行了P(sv)操作,他将得到信号量,并可以进入临界区,使sv减1,。而第二个进程将被阻止进入临界
区,因为当它试图执行P(sv)时,sv为0,他会被挂起以等待第一个进程离开临界区并执行V(sv)释放信号量,这时第二个进程就可以恢复运行。
四、相关函数
1、创建信号量集(每次创建一个多多个信号量)
头文件:#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/sem.h>
函数原型:int semget(key_t key,int nsems,int semflg);
返回值:调用成功返回IPC标识符,调用失败返回-1;
参数:
key:所创建或打开信号量集的键值,也可以有函数 ftok 生成(不同于fork)
nsems:表示创建的信号量集中信号量的个数,该参数只在创建信号量集时有效
semflg: IPC_CREAT:如果IPC存在,则打开它,若不存在,则创建IPC资源。
IPC_EXCL:不能单独使用,没有意义;当与IPC_CREAT搭配使用时表示:若IPC不存在则创建IPC资源,若存在,则产生错 误。二者一 起使用用来保证所得的对象是新建的,而不是打开已有的对象。
2、执行在信号量集上的控制操作
头文件:#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/sem.h>
函数原型:int semctl(int semid,int semnum,int cmd, …);
返回值:调用成功返回一个正数,调用失败返回-1。
参数:semid:信号量集IPC标识符,因为信号量一般是作为一个信号量集使用的,而不是一个单独的信号量。所以在信号量集的操作中,不但要知道IPC关键字值,也要知道信号量集中的具体的信号量。
semnum:操作信号在信号量集中的编号
cmd:系统设置了三种操作:
IPC_STAT:读取一个信号量集的数据结构semid_ds,并将其储存在semun中的buf参数。
IPC_SET:设置信号量集的数据结构senid_ds中的元素ipc_perm,其值取自semun中的buf参数。
IPC_RMID:将信号量集从内存中删除。
3、操作信号量
头文件:#include<sys/types.h>
#include<sys/ipc.h>
#include<sys/sem.h>
函数原型:int semop(int semid,struct sembuf * sops,unsigned nsops);
返回值:调用成功返回0,调用失败返回-1。
参数:semid:信号量集标识码
nsops:信号结构的数量,恒大于或等于1.
sops:指向寻出信号操作结构的数组指针,信号操作结构的原型如下:
struct sembuf
{
unsigned short sem_num; //操作信号在信号量集中的编号,第一个编号为0.
short sem_op;
short sem_flg; //信号操作标志,可能的选择有两种:
IPC_NOWAIT:对信号的操作不能满足时,semop()不会阻塞,并立即返回,同时设定错误信息;
SEM_UNDO:程序结束时(无论正不正常结束),保证信号值会被重设为semop()调用前的值。这样做的目的在于避免程序在异常情况下结束时未将锁定的资源解锁,造成该资源永远锁定。
};
五、代码实现:



Linux - 进程间通信 - 信号量的更多相关文章
- Linux进程间通信--信号量
信号量绝对不同于信号,一定要分清,关于信号,上一篇博客中已经说过,如有疑问,请移驾! 信号量 一.是什么 信号量的本质是一种数据操作锁,它本身不具有数据交换的功能,而是通过控制其他的通信资源(文件 ...
- linux进程间通信-信号量(semaphore)
一 为什么要使用信号量 为了防止出现因多个程序同时访问一个共享资源而引发的一系列问题,我们需要一种方法,它可以通过生成并使用令牌来授权,在任一时刻只能有一个执行线程访问 代码的临界区域.临界区域是指执 ...
- Linux进程间通信—信号量
二.信号量(semophore) 信号量是一种计数器,可以控制进程间多个线程或者多个进程对资源的同步访问,它常实现为一种锁机制.实质上,信号量是一个被保护的变量,并且只能通过初始化和两个标准的原子操作 ...
- Linux进程间通信(二):信号集函数 sigemptyset()、sigprocmask()、sigpending()、sigsuspend()
我们已经知道,我们可以通过信号来终止进程,也可以通过信号来在进程间进行通信,程序也可以通过指定信号的关联处理函数来改变信号的默认处理方式,也可以屏蔽某些信号,使其不能传递给进程.那么我们应该如何设定我 ...
- Linux进程间通信(五):信号量 semget()、semop()、semctl()
这篇文章将讲述别一种进程间通信的机制——信号量.注意请不要把它与之前所说的信号混淆起来,信号与信号量是不同的两种事物.有关信号的更多内容,可以阅读我的另一篇文章:Linux进程间通信 -- 信号.下面 ...
- 【转载】Linux的进程间通信-信号量
原文:Linux的进程间通信-信号量 Linux的进程间通信-信号量 版权声明: 本文章内容在非商业使用前提下可无需授权任意转载.发布. 转载.发布请务必注明作者和其微博.微信公众号地址,以便读者询问 ...
- Linux进程间通信IPC学习笔记之同步二(SVR4 信号量)
Linux进程间通信IPC学习笔记之同步二(SVR4 信号量)
- Linux进程间通信IPC学习笔记之同步二(Posix 信号量)
Linux进程间通信IPC学习笔记之同步二(Posix 信号量)
- Linux进程间通信——使用信号量
这篇文章将讲述别一种进程间通信的机制——信号量.注意请不要把它与之前所说的信号混淆起来,信号与信号量是不同的两种事物.有关信号的更多内容,可以阅读我的另一篇文章:Linux进程间通信——使用信号.下面 ...
随机推荐
- Java面试08|Java重要的类和相关的方法
1.深入理解Class类及其中的方法 获取Class类的方法: 1.调用Object类的getClass()方法来得到Class对象,这也是最常见的产生Class对象的方法.2.使用Class类的中静 ...
- 3297: [USACO2011 Open]forgot
3297: [USACO2011 Open]forgot Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 69 Solved: 51[Submit][ ...
- python 语法笔记(一)
#python3里面input默认接收到的事str类型,而python2里面却认为是int类型n=int(input('请输入想要第几个数')) #如果将int省去,python3中该程序将会报错a, ...
- Linux centos7环境下安装Nginx
Linux centos7环境下安装Nginx的步骤详解 1. 首先到Nginx官网下载Nginx安装包 http://nginx.org/download/nginx-1.5.9.tar.gz ...
- AOP执行增强-Spring 源码系列(5)
AOP增强实现-Spring 源码系列(5) 目录: Ioc容器beanDefinition-Spring 源码(1) Ioc容器依赖注入-Spring 源码(2) Ioc容器BeanPostProc ...
- Python中三种基本结构的语句
选择语句 if 条件判断 : # 条件可以加括号也可以不加括号 -- else: -- Python中没有switch语句这是可以使用if exp:.... elif exp:来代替 if 判断条件1 ...
- Django ORM模型的一点体会
作者:Vamei 出处:http://www.cnblogs.com/vamei 严禁转载. 使用Python的Django模型的话,一般都会用它自带的ORM(Object-relational ma ...
- Cassandra-java操作——基本操作
接着上篇博客,我们来谈谈java操作cassandra; 上篇博客的环境:jdk1.7 + python2.7.10 + cassandra2.2.8; 由于2.2.8没有对应的驱动文档,那么我们就用 ...
- Oracle数据块损坏的恢复实例
测试环境:11.2.0.4 1.构建数据块损坏的测试环境 2.有备份:常规恢复坏块 3.无备份:跳过坏块 1.构建数据块损坏的测试环境 1.1 创建测试表 --Create Table t_test ...
- 快乐Node码农的十个习惯 转
从问世到现在将近20年,JavaScript一直缺乏其它有吸引力的编程语言,比如Python和Ruby,的很多优点:命令行界面,REPL,包管理器,以及组织良好的开源社区.感谢Node.js和npm, ...