分享
 
 
 

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

王朝system·作者佚名  2006-11-24
窄屏简体版  字體: |||超大  

资源共享是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算法给出了信号量的一种实现,为整值对象定义了两个了原语操作:P和V。其C描述如下:

void P(sem)

int *sem;

{

while (*sem<=0);

(*sem)--;

}

void V(sem)

int *sem;

{

(*sem)++;

}

但上述算法不能在用户空间编程,因为①sem指向的信号量变量不能在进程间共享,它们有自己的数据段;②函数非原子执行,内核可在任何时候中断一个进程;③若sem为0,进程并不释放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定义。若flags的IPC_CREAT位被置位,则当该集合不存在时系统就创建之。因此各进程可都用置IPC_CREAT位的flags参数来获取信号量集合的标识符,不需要由某一进程事先创建。若flags为IPC_PRIDVATE则不管同键值的信号量集合是否存在系统都建立之,并返回下一个可用的标识符。

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

①取消信号量集合

int semctl(sid,count,IPC_RMID,0)

int sid; /*信号量集合标识符*/

int count; /*信号量集合中元素个数*/

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

信号量集合刚建立时,各信号量的初值不确定,需要设定初值。初值的设定可用SETALL或SETVAL命令。若用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个信号量,一次仅能设定一个信号量的初值。

③查询信号量集合的当前值

查询信号量集合的当前值可用GETALL或GETVAL命令。若用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.2、SCOOpenSever3.X及5.X上运行通过。

 
 
 
免责声明:本文为网络用户发布,其观点仅代表作者个人观点,与本站无关,本站仅提供信息存储服务。文中陈述内容未经本站证实,其真实性、完整性、及时性本站不作任何保证或承诺,请读者仅作参考,并请自行核实相关内容。
2023年上半年GDP全球前十五强
 百态   2023-10-24
美众议院议长启动对拜登的弹劾调查
 百态   2023-09-13
上海、济南、武汉等多地出现不明坠落物
 探索   2023-09-06
印度或要将国名改为“巴拉特”
 百态   2023-09-06
男子为女友送行,买票不登机被捕
 百态   2023-08-20
手机地震预警功能怎么开?
 干货   2023-08-06
女子4年卖2套房花700多万做美容:不但没变美脸,面部还出现变形
 百态   2023-08-04
住户一楼被水淹 还冲来8头猪
 百态   2023-07-31
女子体内爬出大量瓜子状活虫
 百态   2023-07-25
地球连续35年收到神秘规律性信号,网友:不要回答!
 探索   2023-07-21
全球镓价格本周大涨27%
 探索   2023-07-09
钱都流向了那些不缺钱的人,苦都留给了能吃苦的人
 探索   2023-07-02
倩女手游刀客魅者强控制(强混乱强眩晕强睡眠)和对应控制抗性的关系
 百态   2020-08-20
美国5月9日最新疫情:美国确诊人数突破131万
 百态   2020-05-09
荷兰政府宣布将集体辞职
 干货   2020-04-30
倩女幽魂手游师徒任务情义春秋猜成语答案逍遥观:鹏程万里
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案神机营:射石饮羽
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案昆仑山:拔刀相助
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案天工阁:鬼斧神工
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案丝路古道:单枪匹马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:与虎谋皮
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:李代桃僵
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案镇郊荒野:指鹿为马
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:小鸟依人
 干货   2019-11-12
倩女幽魂手游师徒任务情义春秋猜成语答案金陵:千金买邻
 干货   2019-11-12
 
推荐阅读
 
 
 
>>返回首頁<<
 
靜靜地坐在廢墟上,四周的荒凉一望無際,忽然覺得,淒涼也很美
© 2005- 王朝網路 版權所有