APUE学习笔记(26)-进程间通信之信号量

By:             潘云登

Date:          2009-8-30

Email:         intrepyd@gmail.com

Homepage: http://blog.csdn.net/intrepyd

Copyright: 该文章版权由潘云登所有。可在非商业目的下任意传播和复制。

对于商业目的下对本文的任何行为需经作者同意。


写在前面

1.          本文内容对应《UNIX环境高级编程》(2)》第15章。

2.          总结了进程间通信的一种机制——信号量的基本概念和使用方法。

3.          希望本文对您有所帮助,也欢迎您给我提意见和建议。


信号量

信号量(semaphore)是一个计数器,用于多进程对共享数据对象的访问。为了获得共享资源,进程需要1)测试控制该资源的信号量;2)若此信号量的值为正,则进程可以使用该资源。进程将信号量减1,表示它使用了一个资源单位;3)若此信号量的值为0,则进程进入休眠状态,直至信号量值大于0,进程被唤醒后,返回第1)步。当进程不再使用由一个信号量控制的共享资源时,该信号量增1。如果有进程正在休眠等待此信号量,则唤醒它们。常用的信号量形式被称为二元信号量,它控制单个资源,初始值为1


创建信号量

 

XSI使用信号量集,即含有一个或多个信号量的集合,而非单个信号量。内核为每个信号量集设置一个semid_ds结构,类似于消息队列,它包含ipc_perm结构,用以规定信号量的权限和所有者。每个信号量则由一个无名结构表示。

struct semid_ds {

     struct ipc_perm  sem_perm;  /* see Section 15.6.2 */

     unsigned short   sem_nsems; /* # of semaphores in set */

     time_t           sem_otime; /* last-semop() time */

     time_t           sem_ctime; /* last-change time */

     .

};

 

struct {

     unsigned short  semval;   /* semaphore value, always >= 0 */

     pid_t           sempid;   /* pid for last operation */

     unsigned short  semncnt;  /* # processes awaiting semval>curval */

     unsigned short  semzcnt;  /* # processes awaiting semval==0 */

     .

};

         要创建新的信号量集或者引用一个现存信号量集,需要调用semget函数。创建方法与消息队列一样,或者keyIPC_PRIVATE,或者key当前未与信号量相结合且flag中指定了IPC_CREAT位。新信号量集的访问权限根据flag中的访问权限位设置。nsems参数是该集合中的信号量数。如果是创建新集合,则必须指定nsems,如果引用一个现存的集合,则将nsems指定为0。一个缺点是,创建信号量集(semget)与对其赋初值(semctl)是分开的。

#include <sys/sem.h>

int semget(key_t key, int nsems, int flag);

Returns: semaphore ID if OK, -1 on error

         若执行成功,semget函数将返回信号量集ID,用于其它操作。


操作信号量集

semctl函数包含了多种信号量操作。

#include <sys/sem.h>

int semctl(int semid, int semnum, int  cmd, ... /* union semun arg */);

 

union semun {

     int              val;    /* for SETVAL */

     struct semid_ds *buf;    /* for IPC_STAT and IPC_SET */

     unsigned short  *array;  /* for GETALL and SETALL */

};

依赖于所请求的命令,第四个参数是可选的,如果使用该参数,则其类型为semun,它是多个特定命令参数的联合。cmd参数指定下列10中命令中的一种,在semid指定的信号量集上执行此命令。其中有5条命令是针对一个特定的信号量,它们用semnum指定该信号量集中的一个信号量成员,semnum值在0nsems-1之间。

l          IPC_STAT,获取信号量集的semid_ds结构,并存放在由arg.buf指向的结构中。

l          IPC_SET,按由arg.buf执行结构中的值设置与此信号量集相关的三个字段:sem_perm.uidsem_perm.gidsem_perm.mode。调用进程必须具有超级用户权限,或者其有效用户ID等于sem_perm.cuidsem_perm.uid

l          IPC_RMID,从系统中删除该信号量集,这种删除立即发生。仍在使用此信号量集的其它进程在下一次操作信号量集时,将出错返回-1errno设置为EIDRM调用进程必须具有超级用户权限,或者其有效用户ID等于sem_perm.cuidsem_perm.uid

l          GETVAL,返回成员semnumsemval值。

l          SETVAL,设置成员semnumsemval值,该值由arg.val指定。

l          GETPID,返回成员semnumsempid值。

l          GETNCNT,返回成员semnumsemncnt值。

l          GETZCNT,返回成员semnumsemzcnt值。

l          GETALL,取该信号量集中所有信号量的值,并将它们存放在由arg.array指向的数组中。

l          SETALL,按arg.array指向的数组中的值,设置该信号量集中所有信号量的值,用以初始化信号量集。

对于除GETALL以外的所有GET命令,semctl函数都返回相应的值,其它命令则返回0


获取和释放信号量

获取和释放信号量通过semop函数完成,它是一个原子操作。

#include <sys/sem.h>

int semop(int semid, struct sembuf semoparray[], size_t nops);

Returns: 0 if OK, -1 on error

struct sembuf {

   unsigned short  sem_num;  /* member # in set (0, 1, ..., nsems-1) */

   short           sem_op;   /* operation (negative, 0, or positive) */

   short           sem_flg;  /* IPC_NOWAIT, SEM_UNDO */

};

         其中,参数semoparray是一个指针,它指向一个信号量操作数组,信号量操作由sembuf结构表示。参数nops规定该操作数组的元素个数。对信号量集中成员sem_num的操作由相应的sem_op值规定:

l          sem_op为正,这对应于进程要释放的资源数,sem_op值将加到信号量的值上。

l          sem_op为负,表示进程要获取由该信号量控制的资源。如果信号量的值大于或等于sem_op的绝对值,则从信号量值中减去sem_op的绝对值。如果信号量值小于sem_op的绝对值,即资源不能满足要求,则

²         若指定了IPC_NOWAIT,则semop出错返回-1errno设置为EAGAIN

²         若未指定IPC_NOWAIT,则该信号量的semncnt值加1,调用进程进入休眠状态,直到1)此信号量变成大于或等于sem_op的绝对值,这时,此信号量的semncnt值减1,并且从信号量值中减去sem_op的绝对值;2)从系统中删除此信号量,semop出错返回-1errno设置为EIDRM3)捕捉到一个信号并从处理函数返回,则信号量的semncnt值减1semop出错返回-1errno设置为EINTR

l          sem_op0,表示调用进程希望等待到该信号量值变为0。如果当前信号量值是0,则semop立即返回。如果当前信号值不是0,则

²         若指定了IPC_NOWAIT,则semop出错返回-1errno设置为EAGAIN

²         若未指定IPC_NOWAIT,则该信号量的semzcnt值加1,调用进程进入休眠状态,直到1)此信号量值变为0,这时,此信号量的semncnt值减12)从系统中删除此信号量,semop出错返回-1errno设置为EIDRM3)捕捉到一个信号并从处理函数返回,则信号量的semncnt值减1semop出错返回-1errno设置为EINTR

如果希望内核在进程退出时,能够检查并释放该进程占有的信号量,需要为sem_flg字段指定SEM_UNDO标志。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值