转载:UNIX多用户系统下信号量操作详解

原创 2007年09月15日 12:38:00

UNIX多用户系统下信号量操作详解

 

 

 


   资源共享是UNIX多用户系统的一个重要特征,信号量(SEMAPHORE)则是防止两个或多个进程同时访问共享资源的一种机制。在信号量机制实现之前,通常采用加锁文件的方法,其算法描述如下:

加锁算法


int lock(lockfile)
/*
返回值0代表成功,其它为失败
*/
char *lockfile; /*
加锁文件名
*/
{
intfd,ret=0;
extern int errno;
if((fd=open(lockfile,O_WRONLY|O_CREAT|O_EXCL,0666))==-1
&&errno==EEXIST) ret=1;
return(ret);
}

解锁算法


unlock(lockfile)
char *lockfile; /*
锁文件名
*/
{
unlink(lockfile);
}

这种方法对访问共享资源次数较少的进程是可行的,但对重载的使用则开销太大了,况且一旦加锁失败则进程不知何时可以再试;当系统崩溃或重启动时,加锁文件可能会被忘掉了。


Dijkstra
发表的Dekker算法给出了信号量的一种实现,为整值对象定义了两个了原语操作:PV。其C描述如下
:

void P(sem)
int *sem;
{
while (*sem<=0);
(*sem)--;
}

void V(sem)
int *sem;
{
(*sem)++;
}

但上述算法不能在用户空间编程,因为
sem指向的信号量变量不能在进程间共享,它们有自己的数据段;函数非原子执行,内核可在任何时候中断一个进程;sem0,进程并不释放CPU

所以信号量必须由内核提供,它可在进程间共享数据,可执行原子操作(即一组操作要么全部执行,要么都不执行),可在一个进程阻塞时将CPU给另外一个进程。


UNIXSYSTEMV
以一个长整数的键值作为信号量集合的唯一标识,信号量通常由下列元素组成
:

信号量的值
,

操作该信号量的最后一个进程的进程标识
,

等待增加该信号量的值的进程数
,

等待该信号量的值为0的进程数。


与之有关的系统调用如下
:

#include <sys/types.h>
#include <sys/ipc.h>
#include <sys/sem.h>

int semget(key,count,flags)
/*
获取信号量集合的标识符
*/
key_tkey; /*
信号量集合的键
*/
intcount; /*
信号量集合中元素个数
*/
intflags; /*
任选参数
*/
/*
返回信号量集合标识符,若出错则返回
-1*/

int semop(sid,ops,nops) /*
信号量操作
*/
int sid; /*
信号量集合标识符
*/
struct sembuf *ops; /*
信号量操作结构的指针
*/
intnops; /*
信号量操作结构的个数
*/
/*
返回运算完成前该组信号量中最后一个被运算的信号量的

,若出错则返回
-1*/

int semctl(sid,semnum,cmd,arg)
/*
控制信号量操作
*/
intsid; /*
信号量集合标识符
*/
intsemnum; /*
信号量元素编号
*/
intcmd; /*
控制命令
*/
union semun{
intval;
struct semid_ds *buf;
ushort*array;} arg; /*
命令参数
*/


系统调用semget用来把信号量集合的键值译成代表信号量集合的标识符,该集合中有count个元素,其存取权限定义与文件相同,flags定义。若flagsIPC_CREAT位被置位,则当该集合不存在时系统就创建之。因此各进程可都用置IPC_CREAT位的flags参数来获取信号量集合的标识符,不需要由某一进程事先创建。若flagsIPC_PRIDVATE则不管同键值的信号量集合是否存在系统都建立之,并返回下一个可用的标识符。


系统调用semctl在一组信号量上做各种控制操作,诸如信号量集合的初始化、删除和状态查询等。常用的操作及相关的命令格式如下
:

取消信号量集合


int semctl(sid,count,IPC_RMID,0)
int sid; /*
信号量集合标识符
*/
int count; /*
信号量集合中元素个数
*/

设置信号量集合的初值(初始化
)

信号量集合刚建立时,各信号量的初值不确定,需要设定初值。初值的设定可用SETALLSETVAL命令。若用SETALL命令,其格式为
:

int semctl(sid,count,SETALL,arg)
int sid; /*
信号量集合标识符
*/
int count; /*
信号量集合中元素个数
*/
ushort *arg; /*
命令参数
*/

该命令把数组arg中的前count个值依次赋给集合中各信号量,一次可设定多个信号量的初值。


若用SETVAL命令,其格式为
:

int semctl(sid,semnum,SETVAL,arg)
int sid; /*
信号量集合标识符
*/
int semnum; /*
信号量元素编号
*/
int arg; /*
命令参数
*/

该命令将arg的值赋给集合中第semnum个信号量,一次仅能设定一个信号量的初值。


查询信号量集合的当前值


查询信号量集合的当前值可用GETALLGETVAL命令。若用GETALL命令,其格式为
:

int semctl(sid,count,GETALL,arg)
int sid; /*
信号量集合标识符
*/
int count; /*
信号量集合中元素个数
*/
ushort *arg; /*
命令参数
*/

该命令把信号量集合中各信号量的当前值返回到数组arg中。


若用GETVAL命令,其格式为
:

int semctl(sid,semnum,GETVAL,0)
int sid; /*
信号量集合标识符
*/
int semnum; /*
信号量元素编号
*/

该命令把集合中第semnum个信号量的当前值作为调用的返回值。


查询某个信号量的等待进程数


当一个进程要执行信号量操作时若条件不具备则被阻塞,有关信号量的等待进程数也相应变化。


通过GETNCNT命令可查询等待信号量增值的进程数,其格式如下
:

int semctl(sid,semnum,GETNCNT,0)
int sid; /*
信号量集合标识符
*/
int semnum; /*
信号量元素编号
*/

该命令把等待第semnum个信号量增值的进程数作为调用的返回值。


通过GETZCNT命令可查询等待信号量值为0的进程数,其格式如下
:

int semctl(sid,semnum,GETZCNT,0)
int sid; /*
信号量集合标识符
*/
int semnum; /*
信号量元素编号
*/

该命令把等待第semnum个信号量值为0的进程数作为调用的返回值。


至于其它的控制命令,因不常用而不再累述。


系统调用semop用来对信号量集合中的一个或多个信号量进行操作,操作命令由用户提供的操作结构数组来定义,该结构如下
:

struct sembuf{
short sem_num; /*
信号量在集合中的下标
*/
short sem_op; /*
操作值
*/
short sem_flg; /*
操作标志
*/
};

系统从用户地址空间读信号量操作结构数组,并核实信号量下标的合法性及进程是否具备读或修改信号量所必需的权限。若权限不够则调用失败;若进程必须睡眠,则它将已操作过的信号量恢复为该系统调用开始时的值,然后它就睡眠,直到它等待的事件发生时再重新执行该系统调用。由于系统将操作数组保存在一个全局数组中,因此若它必须重新执行该调用的话,它必须重新从用户空间读该数组。这样,操作按原语方式执行--或一次做完或根本不做。


系统根据操作值来改变信号量的值:若操作值为正,系统就增加信号量的值并唤醒所有等待信号量增值的进程;若操作值是0,系统就检查信号量的值:如果为0,就继续数组中的其它操作;否则把等待信号量的值为0的睡眠进程数加1,然后睡眠;若操作值为负且其绝对值不超过信号量的值,系统就把操作值(一个负数)加到信号量值上,如果结果为0则系统就唤醒所有等待信号量的值为0的睡眠进程;若信号量的值小于操作值的绝对值,系统就让进程睡眠在"等待信号量增值"这一事件上。


当进程在信号量操作过程中睡眠时,它睡眠在可中断级上,因此当它接收到软中断信号时就被唤醒了。用户可在操作标志中设置IPC_NOWAIT标志以防止进程睡眠。

如果进程执行了一个信号量操作,锁住了某些资源,却没有恢复信号量的值就退出了(如收到kill信号),那么就可能出现危险情况。为了避免这类问题,用户可在操作标志中设置SEM_UNDO标志。当进程退出时,系统便撤除该进程做过的每个信号量操作的影响。

值得指出的是,当你使用两个或多个信号量时,死锁总是可能的,系统并不能检查多个信号量间的死锁。


本文所用算法及调用格式均已在SCOUNIX3.2SCOOpenSever3.X5.X上运行通过。

 

相关文章推荐

UNIX多用户系统下信号量操作详解

UNIX多用户系统下信号量操作详解http://www.sina.com.cn 2006年10月30日 22:18  ChinaByte  资源共享是UNIX多用户系统的一个重要特征,信号量(SEMA...
  • haisi05
  • haisi05
  • 2011年06月22日 00:03
  • 304

操作系统信号量PV操作题若干

  • 2009年01月15日 11:55
  • 6KB
  • 下载

操作系统信号量PV操作题若干

  • 2010年12月18日 10:41
  • 44KB
  • 下载

PV操作及信号量实用实例详解

学习PV操作之前,我们首先来了解两个很基础的概念: 同步、互斥: 同步:其实说同步还不如说”协作“,就是我们的目标只有一个,我们奔着同一个目标去的,都是在大家的努力下共同完成这么一件事情。...
  • wuye
  • wuye
  • 2016年10月31日 01:11
  • 262

信号量操作集

  • 2013年11月27日 09:51
  • 38KB
  • 下载

信号量的读写操作,你懂的OS

  • 2012年01月13日 22:44
  • 999B
  • 下载

pv操作及信号量实用实例详解

学习PV操作之前,我们首先来了解两个很基础的概念: 同步、互斥: 同步:其实说同步还不如说”协作“,就是我们的目标只有一个,我们奔着同一个目标去的,都是在大家的努力下共同完成这么一件事情。还是比较...

jdbc连接Oracle数据库实现学生管理系统(用数据库连接池支持多用户操作同一数据库)

Hello,大家好!今天是我第一次写微博,经验不足,希望大家多多包涵,给我多提提建议或意见。我为大家带来一用个jdbc连接Oracle数据库实现学生管理系统的项目,大家如果有正在做这方面的项目,可以拿...

linux/unix信号量的值

或许有许多程序员对linux信号量的用法,信号令的值究竟如何计算,用户如何获得?本篇文章江告诉你如何获得让你迷惑的信号的值! #include #include #include...

UNIX/LINUX编程学习之进程通信--信号量

转自: http://shihaiyang.iteye.com/blog/492306 有关结构体  1.sem  C代码   struct sem {   ...
  • hcwzq
  • hcwzq
  • 2011年08月14日 22:45
  • 386
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:转载:UNIX多用户系统下信号量操作详解
举报原因:
原因补充:

(最多只允许输入30个字)