《进程共享资源信号量控制详细实现(源码及解释)》由会员分享,可在线阅读,更多相关《进程共享资源信号量控制详细实现(源码及解释)(21页珍藏版)》请在金锄头文库上搜索。
1、信号量信号量信号量(Semaphore)简单的说就是用来控制多个进程对共享资源使用的计数器。它 是常被用作一种锁定保护机制,当某个进程对资源进行操作时阻止其他进程对该资 源的访问。需要注意的是,System V 中的的信号量对象实际上是信号量的集合 (set),它可以包含多个信号量,控制多个共享资源。有关的数据结构有关的数据结构和消息队列一样,我们在介绍他的使用前先介绍一些相关的数据结构: 1.sem 前提提到,信号量对象实际是多个信号量的集合。在 Linux 系统中,这种集合是 以数组的形式实现的。数组的每个成员都是一个单独的信号量,它们在系统中是以 sem 结构的形式存储的。Sem 的结构
2、在 Linux 系统 linux/sem.h 中定义是这样的: /* One semaphore structure for each semaphore in the system. */ Struct semShort sempid; /*pid of last operation*/Ushort semval; /*current value*/Ushort semncnt; /*num procs awaiting increase in semval*/Ushort semzcnt; /*num procs awaiting semval=0*/ ; 其中, Sem_pid 成员保存
3、了最近一次操作信号量进程的 pid。 Sem_semval 成员保存着信号量的计数值。 Sem_semncnt 成员保存着等待使用资源的进程数目。 Sem_semzcnt 成员保存等待资源完全空闲的进程数目。 2.semun Semun 联合在 senctl()函数中使用,提供 senctl()操作所需要的信息。它在 Linux 系 统 linux/sem.h 中定义是这样的: /*arg for semctl system calls */ Union semunInt val; /*value for SETVAL*/Struct semid_ds *buf; /*buffer for I
4、PC_STAT /*array for GETALL /* buffer for IPC_INFO*/Void *_pad; ; 前三个参数在对 senctl()函数介绍中会讲到,这里暂时先不管它们。后两个参数是 Linux 系统所独有的,只是系统的内核中使用。 3. semufsemuf 结构被 semop()函数(后面会讲到)用来定义对信号量对象的基本操作。它 在 linux/sem.h 中是这样定义的: /*semop system calls takes an array of these.*/ Stcuct sembufUnsigned short sem_num; /*semaph
5、ore index in array*/Short sem_op; /*semaphore operation*/Short sem_flg; /*operation flags*/ ; 其中, Sem_num 成员为接受操作的信号量在信号量数组中的序号(数组下标) 。 Sem_op 成员定义了进行的操作(可以是正,负和零) 。 Sem_flg 是控制操作行为的标志。 如果 sem_op 是负值,就从指定的信号量中减去相应的值。这对应着获取信号量 所监控 的资源操作。如果没有 sem_flg 指定 IPC_NOWAIT 标志,那么,当现有的信号量数 值小于 sem_op 的绝对值(表示现有的资
6、源少于要获取的资源)时,调用 semop()_函 数的进程就会被阻塞知道信号量的数值大于 sem_op 的绝对值(表示有足够的资源被 释放) 。如果 sem_op 是正值,就在指定的信号量中加上相应的值。这对应着释放信号量 所监控 的资源 操作。 如果 sem_op 是零,那么调用 semop()函数的进程就会被阻塞到直对应的信号量 值为零。 这种操作的实质就是等待信号量所监控的资源被全部使用。利用这种资源操作可以 动态监控资源的使用并调整资源的分配,避免不必要的等待。4. Semid_qs 和 msgqid_ds 类似,semid_qs 结构被系统用来存储每个信号量对象的有关信息。它在 Li
7、nux 系统库 linux/sem.h 中是这样定义的: /*One semid data structure for each set of semaphores in the system*/ Struct semid_dsStruct ipc_perm sem_perm; /*permissions. see ipc.h*/_kernel_time_t sem_otime; /*tast semop time*/_kernel_time_t sem_ctime; /*last change time*/Struct sem *sem_base; /*ptr to first semaph
8、ore in array*/Struct sem_queue *sem_pending; /*pending oprations to be prosessed*/Struct sem_queue *sem_pending_last; /*last pending opration*/Struct sem_undo *undo; /*undo requests on this array*/Unsigned short sem_nsems; /*no.of semaphores in array*/ ; 其中 Sem_perm 成员保存了信号量对象的存取权限以及其他一些信息(见上面关于 ipc
9、_perm 结构的介绍) 。 Sem_otime 成员保存了最近一次 semop()操作的时间。Sem_ctime 成员保存了信号量对象最近一次改动发生的时间。 Sem_base 指针保存着信号量数组的起始地址。 Sem_pending 指针保存着还没有进行的操作。 Sem_pending_last 指针保存着最后一个还没有进行的操作。 Sem_undo 成员保存了 undo 请求的数目。 Sem_nsems 成员保存了信号量数组的成员数目。4.8.2 有关的函数有关的函数介绍完有关的数据结构,接下来我们将介绍使用信号量要用到的函数: 1.semget() 使用 semger()函数来建立新的
10、信号量对象或者获取已有的对象的标示符。它在 linux/sem.h 中的函数声明是这样的: 系统调用:Semget() 函数声明:int semget(key_t key,int nsems,int semflg); 返回值:semaphore set IPC identifier on success1on error:errno=EACCESS(permission denied)权限不足EEXIST(set exist,cannot create(IPC_EXCL)信号量已存在,无 法创建EIDRM(set is marked for deletion)信号量待删ENOENT(set d
11、oes nor exisr,no IPC_CREAT was usrd)信号量不 存在,无法打开ENOMEM(Not enough memory to create new set)无足够内存以 创建新信号量ENOSPC(Maximun set limit exceeded)信号量个数已满 函数接受三个参数。其中第一个参数 key 和第三个参数 semflg 和前面讲过的 msgget()函数中的两个参数对应的,作用和取值的意义也相同,读者可以参看 msgget()的有关介绍。函数的第二个参数 nsems 是信号量对象所特有的。它指定了新 生成的信号量对象中信号量的数目,也就是信号量数组成员的
12、个数。在 linux/sem.h 定义了它的上限: #define SEMMSL 32 /*sem_perm.mode);Return; 为什么呢?一位现实没有给 buf 指针分配内存,其指向是不确定的。这种“不定 向”的指针式 c 程序中最危险的陷阱之一。改正这个错误,只需要前提给 buf 指针准 备一块内存。下面是修改过的代码: Void getmode(int sid) Int rc;Union semun sempots;Struct semid_ds mysemds;/*给 buf 指针准备一块内存*/Semopts.buf = /*现在 ok 了*/If(rc=semctl(sid
13、,0,IPC_STAT,semopts))=-1)Perror(“semctl”)Exit(1);Printf(“permission Mode were %on”,semopts.buf-sem_pem.mode);Return;4.8.3 信号量的实例信号量的实例1.背景知识 Semtool 工具通过命令行参数来决定它的行为,这样它可以决定它的行为,这样他可 以被方便的应用于 shell 脚本中。Semtool 提供了和信号量有关的全部功能,包括创建 信号量、操作、删除信号量对象以及更改信号量权限等。使用它,我们可以在命令 行上控制资源的共享。 2.semtool 的命令行语法 建立信号量
14、对象: semtool c (number of semaphores in set) 锁定信号量: semtool l(semaphore number to lock) 解锁信号量的锁定: semtool u (semaphore number to unlock) 改变信号量的权限: semtool m (mode) 删除信号量对象:semtool d 3. semtool 的使用举例Semtool c 5 Semtool 1Semtool u Semtool m 660 Semtool d 4.semtool 的源代码: Semtool 程序的源代码如下: #include #incl
15、uude #include #include #include #inlclude#define SEM_RESOURCE_MAX 1 /*initial value of all semaphores(所有信号量的初 始值)*/Void opensem(int *sid,key_t key); Void createsem(int *sid,key_t key,int members); Void locksem(int sid,int member); Void unloksem(int sid,int member); Void removesem(int sid); Unsigned short get_member_count(int sid); Int getval(int sid,int member); Void dispval(int sid,int member); Void changemode(int sid,char *mode); Void usage(void);Int main(int argc,char*argv) Key_t key;Int semset_id;If(argc=1)Usage();/*Create unique k