信号量的基本概念与使用semget,semop
1、信号量的基本概念
信号量是一个计数器,常用于处理进程或线程的同步问题,特别是对临界资源的同步访问。
临界资源可以简单的理解为在某一时刻只能由一个进程或线程进行操作的资源,这里的资源
可以是一段代码、一个变量或某种硬件资源。信号量的值大于或等于0时表示可供并发进程使用的
资源实体数;小于0时代表正在等待使用临界资源的进程数。
注意:这里的信号量跟信号是没有关系的。
与消息队列类似,linux内核也为每个信号量维护了一个semid_ds 数据结构实例,
在文件/usr/include/linux/sem.h中
struct semid_ds {
struct ipc_perm sem_perm; /* permissions .. see ipc.h */
__kernel_time_t sem_otime; /* last semop time */
__kernel_time_t sem_ctime; /* last change time */
struct sem *sem_base; /* ptr to first semaphore in array */
struct sem_queue *sem_pending; /* pending operations to be processed */
struct sem_queue **sem_pending_last; /* last pending operation */
struct sem_undo *undo; /* undo requests on this array */
unsigned short sem_nsems; /* no. of semaphores in array */
};
2、信号量的创建与使用
linux下使用semget创建或打开信号量集,
int semget(key_t key, int nsems, int semflg);
该函数执行成功则返回一个信号量集的标识符,失败返回-1。返回的参数key是由ftok得到的键值;
第二个参数nsems指明要创建的信号量集包含的信号量个数。如果只是打开信号量,把nsems设置为0即可。该参数只在创建信号量集时有效。
第三个参数semflg为操作标识,可取如下值:
0:取信号量集标识符,若不存在则函数会报错
IPC_CREAT:当semflg&IPC_CREAT为真时,如果内核中不存在键值与key相等的信号量集,则新建一个信号量集;如果存在这样的信号量集,返回此信号量集的标识符
IPC_CREAT|IPC_EXCL:如果内核中不存在键值与key相等的信号量集,则新建一个消息队列;如果存在这样的信号量集则报错
上述semflg参数为模式标志参数,使用时需要与IPC对象存取权限(如0600)进行|运算来确定信号量集的存取权限
错误代码:
EACCESS:没有权限
EEXIST:信号量集已经存在,无法创建
EIDRM:信号量集已经删除
ENOENT:信号量集不存在,同时semflg没有设置IPC_CREAT标志
ENOMEM:没有足够的内存创建新的信号量集
ENOSPC:超出限制
如果用semget创建了一个新的信号量集对象时,则semid_ds结构成员变量的值设置如下:
sem_otime设置为0。
sem_ctime设置为当前时间。
msg_qbytes设成系统的限制值。
sem_nsems设置为nsems参数的数值。
semflg的读写权限写入sem_perm.mode中。
sem_perm结构的uid和cuid成员被设置成当前进程的有效用户ID,gid和cuid成员被设置成当前进程的有效组ID。
--------------------------------------------------
3、信号量的操作
信号量的值与相应资源的使用情况有关,当它的值大于0时,表示当前可用资源的数量,当他的值小于0时,其绝对值表示等待
使用这个资源的进程个数。信号量的值仅能由PV操作来改变。
在linux下,pv操作通过调用函数semop实现。该函数定义在头文件sys/sem.h中,原型:
int semop(int semid, struct sembuf *sops, unsigned nsops);
对信号量集标识符为semid中的一个或多个信号量进行P操作或V操作
semid:信号量集标识符
sops:指向进行操作的信号量集结构体数组的首地址,此结构的具体说明如下:
struct sembuf {
short semnum; /*信号量集合中的信号量编号,0代表第1个信号量*/
short val;/*若val>0进行V操作信号量值加val,表示进程释放控制的资源 */
/*若val<0进行P操作信号量值减val,若(semval-val)<0(semval为该信号量值),则调用进程阻塞,直到资源可用;若设置IPC_NOWAIT不会睡眠,进程直接返回EAGAIN错误*/
/*若val==0时阻塞等待信号量为0,调用进程进入睡眠状态,直到信号值为0;若设置IPC_NOWAIT,进程不会睡眠,直接返回EAGAIN错误*/
short flag; /*0 设置信号量的默认操作*/
/*IPC_NOWAIT设置信号量操作不等待*/
/*SEM_UNDO 选项会让内核记录一个与调用进程相关的UNDO记录,如果该进程崩溃,则根据这个进程的UNDO记录自动恢复相应信号量的计数值*/
};
nsops:进行操作信号量的个数,即sops结构变量的个数,需大于或等于1。最常见设置此值等于1,只完成对一个信号量的操作
错误代码:
E2BIG:一次对信号量个数的操作超过了系统限制
EACCESS:权限不够
EAGAIN:使用了IPC_NOWAIT,但操作不能继续进行
EFAULT:sops指向的地址无效
EIDRM:信号量集已经删除
sops为指向sembuf数组,定义所要进行的操作序列。下面是信号量操作举例。
struct sembuf sem_get={0,-1,IPC_NOWAIT}; /*将信号量对象中序号为0的信号量减1*/
struct sembuf sem_get={0,1,IPC_NOWAIT}; /*将信号量对象中序号为0的信号量加1*/
struct sembuf sem_get={0,0,0}; /*进程被阻塞,直到对应的信号量值为0*/
flag一般为0,若flag包含IPC_NOWAIT,则该操作为非阻塞操作。若flag包含SEM_UNDO,则当进程退出的时候会还原该进程的信号量操作,这个标志在某些情况下是很有用的,
比如某进程做了P操作得到资源,但还没来得及做V操作时就异常退出了,此时,其他进程就只能都阻塞在P操作上,于是造成了死锁。若采取SEM_UNDO标志,就可以避免因为进程异常退出而造成的死锁。
4、semctl (得到一个信号量集标识符或创建一个信号量集对象)
int semctl(int semid, int semnum, int cmd, union semun arg)
semid:信号量集标识符
semnum:信号量集数组上的下标,表示某一个信号量
cmd:
命令 |
解 释 |
IPC_STAT |
从信号量集上检索semid_ds结构,并存到semun联合体参数的成员buf的地址中 |
IPC_SET |
设置一个信号量集合的semid_ds结构中ipc_perm域的值,并从semun的buf中取出值 |
IPC_RMID |
从内核中删除信号量集合 |
GETALL |
从信号量集合中获得所有信号量的值,并把其整数值存到semun联合体成员的一个指针数组中 |
GETNCNT |
返回当前等待资源的进程个数 |
GETPID |
返回最后一个执行系统调用semop()进程的PID |
GETVAL |
返回信号量集合内单个信号量的值 |
GETZCNT |
返回当前等待100%资源利用的进程个数 |
SETALL |
与GETALL正好相反 |
SETVAL |
用联合体中val成员的值设置信号量集合中单个信号量的值 |
arg:
union semun {
short val; /*SETVAL用的值*/
struct semid_ds* buf; /*IPC_STAT、IPC_SET用的semid_ds结构*/
unsigned short* array; /*SETALL、GETALL用的数组值*/
struct seminfo *buf; /*为控制IPC_INFO提供的缓存*/
} arg;
5、信号量的应用实例:
server创建一个信号量集,并对信号量循环减1,相当于分配资源。
client执行时jian'cha信号量,如果其值大于0代表有资源可用,继续执行,如果小于等于0代表资源已经分配完毕,进程client推出。
server:
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <stdlib.h> #define SIZE 5 union semun {
int val; /* Value for SETVAL */
struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
unsigned short *array; /* Array for GETALL, SETALL */
struct seminfo *__buf; /* Buffer for IPC_INFO
(Linux-specific) */
}; int main()
{
key_t key;
int semid;
struct sembuf sbuf = {, -, IPC_NOWAIT};
union semun semopts; if ((key = ftok(".", )) == -)
{
perror("ftok error:");
exit();
} semid = semget(key, , IPC_CREAT|); semopts.val = SIZE; //第二个参数,信号量集数组上的下标,表示某一个信号量
if ( semctl(semid, , SETVAL, semopts) == - )
{
perror("semctl error:");
exit();
} while()
{
//第二个参数,指向进行操作的信号量集结构体数组的首地址
//第三个参数:进行操作信号量的个数,即sops结构变量的个数,需大于或等于1。最常见设置此值等于1,只完成对一个信号量的操作
if (semop(semid, &sbuf, ) == -)
{
perror("semop error:");
exit();
} sleep();
} return ;
}
client:
#include <stdio.h>
#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>
#include <stdlib.h> #define SIZE 5 union semun {
int val; /* Value for SETVAL */
struct semid_ds *buf; /* Buffer for IPC_STAT, IPC_SET */
unsigned short *array; /* Array for GETALL, SETALL */
struct seminfo *__buf; /* Buffer for IPC_INFO
(Linux-specific) */
}; int main()
{
key_t key;
int semid;
int semval; if ((key = ftok(".", )) == -)
{
perror("ftok error:");
exit();
} semid = semget(key, , IPC_CREAT|); while()
{ if ( (semval = semctl(semid, , GETVAL, )) == - )
{
perror("semctl error:");
exit();
} if (semval > )
{
printf("still have %d resources can be used\n", semval);
}
else
{
printf("no more resources can be use\n");
} sleep();
} return ;
}
信号量的基本概念与使用semget,semop的更多相关文章
- semget() semop()
semget() 可以使用系统调用semget()创建一个新的信号量集,或者存取一个已经存在的信号量集: 系统调用:semget();原型:intsemget(key_t key,int nsems, ...
- Linux进程间通信(五):信号量 semget()、semop()、semctl()
这篇文章将讲述别一种进程间通信的机制——信号量.注意请不要把它与之前所说的信号混淆起来,信号与信号量是不同的两种事物.有关信号的更多内容,可以阅读我的另一篇文章:Linux进程间通信 -- 信号.下面 ...
- 信号量 Linux函数 semget();semctl();semop();(转)
本文出自:http://blog.csdn.net/ta893115871/article/details/7505560 Linux进程通信之信号量 信号量(semaphore)是变量,是一种特殊的 ...
- 【转载】Linux的进程间通信-信号量
原文:Linux的进程间通信-信号量 Linux的进程间通信-信号量 版权声明: 本文章内容在非商业使用前提下可无需授权任意转载.发布. 转载.发布请务必注明作者和其微博.微信公众号地址,以便读者询问 ...
- Linux 信号量互斥编程
所谓信号量,其实就是一个数字.内核给这个数字赋予一定的含义,让它等于不同的值时所表示的意义不同.这样就可以用它来标示某种资源是否正被使用.信号的分类其实挺多的,主要还是二值和计数器.这里讨论二值 现在 ...
- Linux学习笔记26——信号量
一 信号量的基本概念 信号量:它是一个特殊变量,只允许对它进行等待和发送信号这两种操作. 假设有一个信号量变量sv P(sv):用于等待,如果sv的值大于零,就给它减去1,如果它的值等于零,就挂起该进 ...
- Linux 进程通信之 ——信号和信号量总结
如今最经常使用的进程间通信的方式有:信号,信号量,消息队列,共享内存. 所谓进程通信,就是不同进程之间进行一些"接触",这种接触有简单,也有复杂.机制不同,复杂度也不一 ...
- Linux进程间通信(System V) --- 信号量
信号量 IPC 原理 信号量通信机制主要用来实现进程间同步,避免并发访问共享资源.信号量可以标识系统可用资源的个数.最简单的信号量为二元信号量 下图为 Linux 信号量通信机制的概念图.在实际应用中 ...
- linux编程之信号量编程
信号量当我们在多用户系统,多进程系统,或是两者混合的系统中使用线程操作编写程序时,我们经常会发现我们有段临界代码,在此处我们需要保证一个进程(或是一个线程的执行)需要排他的访问一个资源.信号量有一个复 ...
随机推荐
- 【原创】驱动加载之OpenService
SC_HANDLE WINAPI OpenService( _In_ SC_HANDLE hSCManager, _In_ LPCTSTR lpServiceName, _In_ DWORD dwDe ...
- Centos-7修改yum源为国内的yum源
以centos7为例 ,以 修改为阿里的yum源 1. 备份本地yum源 [root@localhost yum.repos.d]# cp CentOS-Base.repo CentOS-Base.r ...
- man rpcbind(rpcbind中文手册)
本人译作集合:http://www.cnblogs.com/f-ck-need-u/p/7048359.html RPCBIND() BSD System Manager's Manual RPCBI ...
- 应用负载均衡之LVS(五):lvs和nginx的wrr加权调度算法规律分析
返回LVS系列文章:http://www.cnblogs.com/f-ck-need-u/p/7576137.html 加权调度算法(wrr)是一种很常见的调度算法.它们按照权重比例进行调度,但实际调 ...
- .NET CORE 实践(3)--Visual Studio 2015 Update 3更新之后DotNetCore.1.0.1-VS2015Tools.Preview2.0.2.exe无法正确安装
打开 https://www.microsoft.com/net/core#windows,点击 https://go.microsoft.com/fwlink/?LinkId=691129下载vs2 ...
- C#中设置窗口在最前显示而其他窗口不能使用
对程序中的一个Form1处理,让其在打开的情况下,其他窗体都无法使用,全部焦点都在他身上. 1.这种方法最简单,直接调用窗体的模态对话框函数显示窗体 Form1.ShowDialog(): 2.设置窗 ...
- npm WARN enoent ENOENT: no such file or directory, open 'C:\Users\package.json'
在使用 npm 命令安装常用的 Node.js web框架模块 express时出现: 解决方法是 在命令行切换到安装nodejs文件下的nodejs\node_modules\npm 后执行npm ...
- 【Java】Properties文件的解析
public abstract class ReadProperties { public ReadProperties() {} /** * 回调函数,由调用者处理 * @param key * @ ...
- Yii2基本概念之——事件(Event)
说起事件(event),我们可是一点都不陌生.现实生活当中的事件无处不在,比如你发了一条微博,触发了一条事件,导致关注你的人收到了一条消息,看到你发的内容:比如你通过支付宝买东西,付了款,触发一个事件 ...
- Ext中defaults与fieldDefaults
不同点:defaults :直接子组件中的默认配置fieldDefaults: 后代组件中的默认配置 相同点:组件自己的配置中指定的值优先