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进程间通信——使用信号.下面 ...
随机推荐
- Android学习总结(十五) ———— Notification(状态栏通知)基本用法
一.Notification基本概念 Notification是一种具有全局效果的通知,它展示在屏幕的顶端,首先会表现为一个图标的形式,当用户向下滑动的时候,展示出通知具体的内容.我们在用手机的时候 ...
- KoaHub.js -- 基于 Koa.js 平台的 Node.js web 快速开发框架之koahub-loader
koahub loader Installation $ npm install koahub-loader Use with koa // 1.model loader var model = ...
- 算法模板——splay区间反转 1
实现的功能:将序列区间反转,并维护 详见BZOJ3223 var i,j,k,l,m,n,head,a1,a2:longint; s1:ansistring; a,b,c,d,fat,lef,rig: ...
- 前端总结·基础篇·JS(二)数组深拷贝、去重以及字符串反序和数组(Array)
目录 这是<前端总结·基础篇·JS>系列的第二篇,主要总结一下JS数组的使用.技巧以及常用方法. 一.数组使用 1.1 定义数组 1.2 使用数组 1.3 类型检测 二.常用技巧 2.1 ...
- App对接支付宝移动支付功能
前段时间看了下app对接支付宝移动支付的功能,并自己总结了下支付宝移动支付的实现流程 一.申请流程 前提是已有现成的应用. 1. 申请地址 https://b ...
- windows phone 8.1常用启动器实例
---恢复内容开始--- 小梦今天给大家分享一下windows phone 8.1常用启动器实例,包括: 电话启动器 短信启动器 邮件启动器 添加约会|备忘到日历 地图启动器 地图路线启动器 wind ...
- 利用Register protocol实现网页调用桌面程序(类似迅雷、QQ等)
前言 我们经常看到 tencent://.. thunder:// 这两种开头的网址,往往觉得很奇怪,很想弄懂其中的原理,是如何实现的,我查找了相关的 资料,终于找到了,跟大家分享下. 原理篇 ...
- Python 爬取qqmusic音乐url并批量下载
qqmusic上的音乐还是不少的,有些时候想要下载好听的音乐,但有每次在网页下载都是烦人的登录什么的.于是,来了个qqmusic的爬虫. 至少我觉得for循环爬虫,最核心的应该就是找到待爬元素所在ur ...
- 检测Windows程序的内存和资源泄漏之原生语言环境
最近接连收到大客户的反馈,我们开发的一个软件,姑且称之为App-E吧,在项目规模特别大的情况下,长时间使用会逐渐耗尽内存,运行越来越缓慢,软件最终崩溃.由于App-E是使用混合语言开发的,主界面使用C ...
- python应用部署--flask
首先必须吐槽一下,python应用部署简直就是有毒...太麻烦了.关键还不能成功部署. 网上很多教程都是说要用nginx和uwsgi.来来回回试了无数次都不行.于是乎,在某一个瞬间,灵感以来,发现了一 ...