进程共享资源信号量控制详细实现(源码及解释).doc_第1页
进程共享资源信号量控制详细实现(源码及解释).doc_第2页
进程共享资源信号量控制详细实现(源码及解释).doc_第3页
进程共享资源信号量控制详细实现(源码及解释).doc_第4页
进程共享资源信号量控制详细实现(源码及解释).doc_第5页
已阅读5页,还剩16页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

信号量信号量(Semaphore)简单的说就是用来控制多个进程对共享资源使用的计数器。它是常被用作一种锁定保护机制,当某个进程对资源进行操作时阻止其他进程对该资源的访问。需要注意的是,System V中的的信号量对象实际上是信号量的集合(set),它可以包含多个信号量,控制多个共享资源。有关的数据结构和消息队列一样,我们在介绍他的使用前先介绍一些相关的数据结构:1. sem前提提到,信号量对象实际是多个信号量的集合。在Linux系统中,这种集合是以数组的形式实现的。数组的每个成员都是一个单独的信号量,它们在系统中是以sem结构的形式存储的。Sem的结构在Linux系统linux/sem.h中定义是这样的:/* One semaphore structure for each semaphore in the system. */Struct sem Short 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成员保存了最近一次操作信号量进程的pid。Sem_semval成员保存着信号量的计数值。Sem_semncnt成员保存着等待使用资源的进程数目。Sem_semzcnt成员保存等待资源完全空闲的进程数目。2.semunSemun联合在senctl()函数中使用,提供senctl()操作所需要的信息。它在Linux系统linux/sem.h中定义是这样的:/*arg for semctl system calls */Union semun Int val; /*value for SETVAL*/ Struct semid_ds *buf; /*buffer for IPC_STAT&SETALL*/ Ushort *array; /*array for GETALL&SETALL*/ Struct seminfo *_buf; /* buffer for IPC_INFO*/ Void *_pad;前三个参数在对senctl()函数介绍中会讲到,这里暂时先不管它们。后两个参数是Linux系统所独有的,只是系统的内核中使用。3. semufsemuf结构被semop()函数(后面会讲到)用来定义对信号量对象的基本操作。它在linux/sem.h中是这样定义的:/*semop system calls takes an array of these.*/Stcuct sembuf Unsigned short sem_num; /*semaphore 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的绝对值(表示现有的资源少于要获取的资源)时,调用semop()_函数的进程就会被阻塞知道信号量的数值大于sem_op的绝对值(表示有足够的资源被释放)。 如果sem_op是正值,就在指定的信号量中加上相应的值。这对应着释放信号量所监控的资源 操作。如果sem_op是零,那么调用semop()函数的进程就会被阻塞到直对应的信号量值为零。这种操作的实质就是等待信号量所监控的资源被全部使用。利用这种资源操作可以动态监控资源的使用并调整资源的分配,避免不必要的等待。 4. Semid_qs 和msgqid_ds类似,semid_qs结构被系统用来存储每个信号量对象的有关信息。它在Linux系统库linux/sem.h中是这样定义的:/*One semid data structure for each set of semaphores in the system*/Struct semid_ds Struct 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 semaphore 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_perm结构的介绍)。Sem_otime成员保存了最近一次semop()操作的时间。Sem_ctime成员保存了信号量对象最近一次改动发生的时间。Sem_base指针保存着信号量数组的起始地址。Sem_pending指针保存着还没有进行的操作。Sem_pending_last指针保存着最后一个还没有进行的操作。Sem_undo成员保存了undo请求的数目。Sem_nsems成员保存了信号量数组的成员数目。4.8.2有关的函数介绍完有关的数据结构,接下来我们将介绍使用信号量要用到的函数:1.semget()使用semger()函数来建立新的信号量对象或者获取已有的对象的标示符。它在linux/sem.h 中的函数声明是这样的:系统调用:Semget()函数声明:int semget(key_t key,int nsems,int semflg);返回值:semaphore set IPC identifier on success 1on error:errno=EACCESS(permission denied)权限不足 EEXIST(set exist,cannot create(IPC_EXCL)信号量已存在,无法创建 EIDRM(set is marked for deletion)信号量待删 ENOENT(set does 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是信号量对象所特有的。它指定了新生成的信号量对象中信号量的数目,也就是信号量数组成员的个数。在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 = &mysemds; /*现在ok了*/ If(rc=semctl(sid,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的命令行语法建立信号量对象: semtool c (number of semaphores in set)锁定信号量: semtool l(semaphore number to lock)解锁信号量的锁定: semtool u (semaphore number to unlock)改变信号量的权限: semtool m (mode)删除信号量对象:semtool d3. semtool的使用举例 Semtool c 5 Semtool 1 Semtool uSemtool m 660Semtool d4.semtool 的源代码:Semtool程序的源代码如下:#include#incluude#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 key via call to ftok()(用ftok()函数创建关键字)*/ Key=ftok(“,”,s); Switch(tolower(argv10) Case c:if(argc!=3) Usage(); Createsem(&semset_id,key,atoi(argv2); Break; Casel:if(argc!=3) Usage(); Opensem(&semset_id,key); Locksem(semset_id,atoi(argv2); Break; Case u:if(argc!=3) Usage(); Opensem(&semset_id,key); Unlocksem(semset_id,atoi(arge2); Break; Cased:opensem(&semset_id,key); Removesem(semset_id); Break; Case m:opensem(&semset_id,key); Changemode(semset_id,argv2); Break; Default:usage(); Return(0);Void opensem(int*sid,key_t key) /*Open the semaphore set-do not create!(打开信号量对象(而不是创建它))*/ If(*sid=semget(key,0,0666)=-1) Printf(“Semaphore set does not exist!n”); Exit(1); Void createsem(int*sid,key_t key,int members) Int cntr; Union semun semopts; If(membersSEMMSL) Prinff(“Sorry,max number of semaphores in a set is %dn”,SEMMSL); Exit(1); Printf(“Attempting to cteate new semaphore set with %d membersn”,members); If(*sid=semget(key,members,IPC_CREAIT|IPC_EXCL|0666)=-1) Fprintfs(stderr,”Semaphore set already exists!n”); Exit(1); Semots.val=SEM_RESOURCE_MAX; /*lnitialize all members (Could be done with SETALL)初始化对象内所有信号量(该操作也可以用SETALL完成)*/For(cntr=0;cntrmembers;cntr+) Semctl(*sid,cntr,SETVAL,semopts);Void locksem(int sid,int member) Struct sembuf sem_lock=0,-1,IPC_NOWALT;If(member(get_member_cout(sid)-1) Fprintf(stderr,”semaphore member%d out of rangn”,member); Return;/*Attempt to luck the semaphore set 尝试锁定信号量*/If(!getvala(sid,member) Fprintf(stderr,”semaphore member%d ouot of rangn”,member); Return;/*Attnmpt to lock the semphore set尝试锁定信号量*/If(!getval(sid,member)) Fprintf(stderr,”Semaphore resources exhausted (no lock)!n”); Exit(1);Sem_lock.sem_num=member; If(semop(sid,&sem_lock,1)=-1) Fprintff(stderr,”Lock faildn”); Exit(1);Else Printf(“Semaphore resources decrememted by one(lockd)n”);Dispval(sid,member);Void unlocksem(int sid,int member) Struct sembuf sem_unlock=member,1,IPC_NOWALT; Int semval; If(member(get_member_count(sid)-1) Fprintf(stderr,”semaphore member%d out of rangn”,member); Return;/*Is the semaphore set locked?判断信号量是否被锁*/Semval=getval(sid,member);If(semval=SEM_RESOURCE_MAX) Fprintf(stderr,”Semaphore not locked!n”);Exit(1); Sem_unlock,sem_num=member;/*Attempt to lock the semaphore set 尝试解除锁定*/If(semop(sid,&sem_unlock,1)=-1) Fprintf(stderr,”Unlock failedn”); Exit(1);Else Printf(“Semaphore resources incremented by one(unlocked)n”; Dispval(sid,member);Void removesem(int sid) Semctl(sid,0,IPC_RMID,0); Printf(“Semaphore removedn”);Unsigned short ger_member_cout(int sid) Union semun semots; Struct semid_ds mysemds; Semopts.buf=&mysemds; /*Return number of menbers in the semaphore set(返回对象内的信号量个数)*/ Return(semopts.buf-sem_nsems);Int getval(int sid,int member) Int semval; Semval=semctl(sid,member,GETVAL.0); Return(semval);Void changemode(int sid,char*mode) Int rc; Union semun semopts; Struct semid_ds mysemds;/*Get current values for internal data structure(获取对象当前的状态)*/Semopts.buf =&mysemds;Rc=semctl(sid,0,IPC_STAT,semopts);If(rc=-1) Perror(“semctl”); Exit(1);Printf(“Old permissions were%on”,semopts,buf-sem_perm.mode);/*change the permissions on the semaphore(读取信号量对象的权限)*/Sscanf(mode,”%ho”,&sempot.buf-sem_pem.mode);/*Update the internal data structure更新权限*/Semctl(sid,0,IPC_SET,semopts);Printf(Updatedn”);Void dispval(int sid,int member) Int semval; Semval=semctl(sid,member,GETVAL,0); Printf(“semval for member%dn”,member,semval);Void usage(void) Fprintf(“stderr,”semtool-A utility for thikering with semaphoresn”); Fprintf(“stderr,”Nusage:semtool4(c)reaten”); Fprintf(stderr,” (l)ockn”); Fprintf(stderr,” (u)nlockn”); Fprintf(stderr,” (d)eleten”); Fprintf(stderr,” (m)oden”); Exit(1);4.9共享内存共享内存(Shared Memory)简单的说就是被多个进程共享的内存。它在各种进程通信方法中是最快的,因为它将是信息直接映射到内存中,省去了其他IPC方法的中间步骤。4.9.1有关的数据机构下面我们介绍几个和共享内存有关的数据结构:1.shmid_ds和前面介绍的两个IPC对象一样,共享内存也有一个给系统内存用来保存相关信息的结构,就是shmid_ds.它在 linux/shm.h中的定义是这样的: Struct shmid_ds Struct ipc_perm shm_perm; /*operation perms*/ Int shm_segsz; /*size of segment (bytes)*/ _kernel_time_t shm_atime: /*last attach time*/ _kernel_time_t shm_dtime: /*last detach time*/ _kernel_time_t shm_ctime; /*last change time*/ _kernel_ipc_pid_t shm_cpid; /*pid of creator*/ _kernel_ipc_pid_t shm_lpid; /*pid of creator*/ Unsigned short shm_nattch; /*no.of current attaches*/ Unsigned short shm_unused; /.*compatibility*/ Void *shm_unused2; /*ditto-used by DIPC*/ Void *shm_unused3; /*unused*/ 其中,Shm_perm成员保存了共享内存对象的存取权限及其他一些信息。Shm_segze成员定义了共享内存大小(以字节胃单位)Shm_atime成员保存了最近一次进程连接共享内存的时间。Shm_dtime成员保存了最近一次进程断开与共享内容的连接时间。Shm_ctime成员保存了最近一次shmid_ds结构内容改变的时间Shm_cpid成员保存了创建共享内容的进程pidShm_lpid成员保存了最近一次连接共享内存的进程pid.Shm_nattch成员保存了与共享内存连接的进程数目。剩下的三个成员被内核保留使用,这里就不介绍了。4.9.2有关的函数接下来我们介绍和共享内存有关的函数:1Sys_shmgrt()函数使用shmget()函数来创建新的获取得已有的共享内存。它在Linux系统linux/shm.h中的定义是这样的:系统调用:shmget()函数声明:int shmget(key_t key,int size,int shmflg); 返回值:shared memory segment identifier on success -1 on error:errno=EINVAL(lnvalid segment size specified指定的共享内存大小非法) EEXIST(Segment exists,cannot create共享内存已存在,无法创建) EIDRM(Segment is marked for deletion,or was remove共享内存待删或已删) ENOENT(Segment does not exist共享内存不存在,无法打开) EACCES(Permission denied权限不足) ENOMEM(Not enough memory to create segment 内存不足,无法创建共享内存)和前面两个IPC对象函数一样,shmget()函数的第一个参数key是共享内存的关键字;第二个参数size是创建的共享内存的大小,以字节为单位。第三个参数shmflg是控制函数行为的标志量,其取值的含义与作用和msgget()及semget()函数的对应参数都是相同的,这里不再赘述。如果操作成功,函数返回共享内存的标识符。下面的代码示范了shmger()函数的使用: Int open_shm(key_t keyval,int segsize) Int shmid:If(shmid=shmget(keyval,segsize,IPC_CREAT|0660)=-1) Return(-1); Return(shmid);2.shmat()函数当一个进程使用shmget()函数得到了共享内存的标志符之后,就可以使用shmat()函数将共享内存映射到进程自己的内存空间内。Shmat()函数在linux系统函数库linux/shm.h中的函数声明如下:系统调用:shmat()函数声明:int shmat (int shmid,char *shmaddr,int shmflg); 返回值:address at which segment was attached to the process,or -1 on error:ereno =EINVAL(invalid IPC ID value or attach address passed)指定的IPC标识符或内存地址非法 ENODMEM(Not enough memory to attach segment)内存不足 EACCES(permission denied)权限不足 第一个参数是共享内存的标识符。第二个参数shmadar指定了共享内存映射的地址。因为这样必须要预先分配内存,十分不便,所以我们在使用时常常将这个参数置零,这样系统会自动为映射分配一块未使用的内存。如果指定了地址,可以给第三个参数shmflg指定SHM_RND标志来强迫将内存大小设定为页面的尺寸.。如果指定了SHM_RDONLY参数,共享内存将被映射成只读。映射成功后,函数返回指向映射内存的指针。下面的这段代码演示了shmat()函数的使用:Char*attach_segment(int shmid) Return(shmat(shmid,0,0);得到了映射内存的指针之后,我们就可以像读写普通内存一样对共享内存进行读写了。3.shmctl()函数和前两个IPC对象一样,共享内存也有一个直接对其进行操作的函数,就是shmctl()函数。它在Linux系统函数库linux/shm.h中的函数声明是这样的:系统调用:shmctl()函数声明:int shmctl(int shmqid,int cmd,struct shmid_ds*buf); 返回值:0 on success -1 on error;errno=EACCES(No read permission and cmd is IPC_STAT进行IPC_STAT)操作时无读权 EFAULT(Address pointed to by buf is invalid with IPC_SETandIPC_STAT commands buf)指定的地址非法 EIDRM(segment was removed during retrieval)操作过程中共享内存被删除 EINVAL(shmqid invalid shmqid)非法 EPERM(IPC_SET or IPC_RMID command was issued,but calling process does not have write(alter)access to the segment)进程无写全这个函数和msgger()函数十分相似,用法也相同。它支持的操作有:IPC_STAT 获得共享内存的信息。IPC_SET 设定共享内存的信息。IPC_RMID 删除共享内存。需要说明的是,当执行IPC-RMID操作时,系统并不是立即将其删除,而只是将其标为待删,然后等待与其连接的进程断开连接。只有当所有的连接都断开以后系统才执行真正的删除操作。当然,如果执行IPC_RMID的时候没有任何连接,删除将是立即执行的。4.shmdt()函数 当一个进程不再需要某个共享内存的映射时,就应该使用shmdt()函数断开映射。它在linux/shm.h中的函数声明如下: 系统调用:shmdt() 函数声明:int shmdt (char*shmaddr); 返回值:-1 on error :errn

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

最新文档

评论

0/150

提交评论