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

来源:互联网 发布:淘宝周点数 编辑:程序博客网 时间:2024/05/21 07:10

转自:
http://shihaiyang.iteye.com/blog/492306

有关结构体 
1.sem 

C代码  收藏代码
  1. struct sem {  
  2.                  short   sempid;        /* pid of last operation */  
  3.                  ushort  semval;        /* current value */  
  4.                  ushort  semncnt;       /* num procs awaiting increase in semval */  
  5.                  ushort  semzcnt;       /* num procs awaiting semval = 0 */  
  6. };  
其中, 
sem_pid 成员保存了最近一次操作信号量的进程的pid。 
sem_semval  成员保存着信号量的计数值。 
sem_semncnt 成员保存着等待使用资源的进程数目。 
sem_semzcnt  成员保存等待资源完全空闲的的进程数目。 

2.semun 
semun联合体在senctl()函数中使用,提供 senctl()操作所需要的信息。 
C代码  收藏代码
  1. union semun {  
  2.                  int val;                /* value for SETVAL */  
  3.                  struct semid_ds *buf;   /* buffer for IPC_STAT & IPC_SET */  
  4.                  ushort *array;          /* array for GETALL & SETALL */  
  5.                  struct seminfo *__buf;  /* buffer for IPC_INFO */  
  6.                  void *__pad;  
  7. };  

3.sembuf 
sembuf结构体被semop()函数用来定义对信号量对象的基本操作 
C代码  收藏代码
  1. struct sembuf {  
  2.          unsigned short  sem_num;        /* semaphore index in array */  
  3.          short           sem_op;         /* semaphore operation */  
  4.          short           sem_flg;        /* operation flags */  
  5. };  
其中, 
sem_num 成员为接受操作的信号量在信号量数组中的序号(数组下标)。 
sem_op  成员定义了进行的操作(可以是正、负和零)。 
sem_flg 是控制操作行为的标志。 

4.semid_qs 
和msgqid_ds类似,semid_qs结构被系统用来储存每个信号量对象的有关信息。 
C代码  收藏代码
  1. struct semid_ds {  
  2.       struct ipc_perm sem_perm;            /* permissions ..  see ipc.h */  
  3.       __kernel_time_t sem_otime;           /* last semop time */  
  4.       __kernel_time_t sem_ctime;           /* last change time */  
  5.       struct sem      *sem_base;           /* ptr to first semaphore in array */  
  6.       struct sem_queue *sem_pending;       /* pending operations to be processed */  
  7.       struct sem_queue **sem_pending_last; /* last pending operation */  
  8.       struct sem_undo *undo;               /* undo requests on this array */  
  9.       unsigned short  sem_nsems;           /* no.  of semaphores in array */  
  10. };  

其中, 
sem_perm  成员保存了信号量对象的存取权限以及其他一些信息。 
sem_otime 成员保存了最近一次semop()操作的时间。 
sem_ctime 成员保存了信号量对象最近一次改动发生的时间。 
sem_base  指针保存着信号量数组的起始地址。 
sem_pending 指针保存着还没有进行的操作。 
sem_pending_last 指针保存着最后一个还没有进行的操作。 
sem_undo  成员保存了 undo请求的数目。 
sem_nsems 成员保存了信号量数组的成员数目。 

有关的函数 
1.semget() 
使用semget()函数来建立新的信号量对象或者获取已有对象的标识符。 
系统调用: semget() 
函数声明: int semget(key_t key,int nsems,int semflg); 
返回值:  semaphore set IPC identifier on success 
C代码  收藏代码
  1. int open_semaphore_set(key_t keyval, int numsems)  
  2. {  
  3.     int sid;  
  4.     if(!numsems) return(-1);  
  5.     if((sid=semget(keyval,numsems,IPC_CREAT|0660))==-1)  
  6.     {     
  7.         return(-1);  
  8.     }  
  9.     return(sid);  
  10. }  
函数的第二个参数 nsems 是信号量对象所特有的,它指定了新生成的信号量对象中信号量的数目,也就是信号量数组成员的个数。 
2.semop() 
使用这个函数来改变信号量对象中各个信号量的状态。 
系统调用: semop() 
函数声明: int semop(int semid, struct sembuf *sops, unsigned int nsops); 
返回值:  0 on success (all operations performed) 
第一个参数 semid是要操作的信号量对象的标识符。 
第二个参数 sops是sembuf的数组,它定义了semop()函数所要进行的操作序列。 
第三个参数 nsops保存着sops数组的长度,也即semop()函数将进行的操作个数。 

3.semctl() 
和消息队列的msgctl()函数类似,semctl()函数被用来直接对信号量对象进行控制 
系统调用:  semctl() 
函数声明:  int semctl(int semid, int semnum, int cmd, union semun arg); 
返回值:   positive integer on success 
比较一下这两个函数的参数我们回发现一些细微的差别。首先,因为信号量对象事实上是多个信息量的集合而非单一的个体,所以在进行操作时,不仅需要指定对象的标识符,还需要用信号量在集合中的序号来指定具体的信号量个体。 

两个函数都有cmd参数, 指定了函数进行的具体操作。 不过,和msgctl()函数相比, semctl()函数可以进行的操作要多得多: 
IPC_STAT  取得信号量对象的 semid_ds 结构信息,并将其储存在 arg 参数中 buf 指针所指内存中返回。 
IPC_SET   用 arg 参数中 buf 的数据来设定信号量对象的的 semid_ds 结构信息。和消息队列对象一样,能被这个函数设定的只有少数几个参数。 
IPC_RMID  从内存中删除信号量对象。 
GETALL    取得信号量对象中所有信号量的值,并储存在 arg 参数中的 array 数组中返回。 
GETNCNT   返回正在等待使用某个信号量所控制的资源的进程数目。 
GETPID    返回最近一个对某个信号量调用semop()函数的进程的 pid。 
GETVAL    返回对象那某个信号量的数值。 
GETZCNT   返回正在等待某个信号量所控制资源被全部使用的进程数目。 
SETALL    用 arg 参数中 array数组的值来设定对象内各个信号量的值。 
SETVAL    用 arg 参数中val成员的值来设定对象内某个信号量的值。 

C代码  收藏代码
  1. int  get_sem_val(int sid, int semnum)  
  2. {  
  3.     return(semctl(sid,semnum,GETVAL,0));  
  4. }  
上面的代码返回信号量对象中某个信号量的值。注意这里 semctl()函数的最后一个参数取的是零,这是因为执行 GETVAL 命令时这个参数被自动忽略了。 
C代码  收藏代码
  1. void init_semaphore(int sid, int semnum, int initval)  
  2. {  
  3.     union semun semopts;  
  4.         semopts.val=initval;  
  5.     semctl(sid, semnum, SETVAL, semopts);  
  6.   
  7. }  
上面的代码用 initval参数来设定信号量对象中某个信号量的值。 
在消息队列和信号量对象中,都有 IPC_STAT 和 IPC_SET 的操作。但是由于传递参数的类型不同,造成了它们在使用上的差别。在 msgctl()函数中,IPC_STAT 操作只是简单的将内核内 msgqid_ds 结 

构的地址赋予buf参数(是一个指针)。而在semctl()函数中, IPC_STAT操作是将 semid_ds 的内容拷贝到 arg 参数的 buf 成员指针所指的内存中。所以,下面的代码会产生错误,而 msgctl()函数的 

类似代码却不会: 
C代码  收藏代码
  1. void getmode(int sid)  
  2. {  
  3.     int rc;  
  4.     union semun semopts;  
  5.     /*下面的语句会产生错误*/  
  6.     if((rc=semctl(sid, 0, IPC_STAT, semopts))==-1)  
  7.     {  
  8.         perror("semctl");  
  9.     }  
  10.     printf("Pemission Mode were %o\n", semopts.buf->sem_perm.mode);  
  11.     return;  
  12. }  
为什么呢?因为实现没有给 buf 指针分配内存,其指向是不确定的。这种“不定向”的指针是 C 程序中最危险的陷阱之一。改正这个错误,只需要提前给 buf 指针准备一块内存。下面是修改过的代码:
C代码  收藏代码
  1. void getmode(int sid)  
  2. {  
  3.     int rc;  
  4.     union semun semopts;  
  5.     struct semid_ds mysemds;  
  6.     /*给buf指针准备一块内存*/  
  7.     semopts.buf=&mysemds;  
  8.   
  9.     /*现在OK了*/  
  10.     if((rc=semctl(sid, 0, IPC_STAT, semopts))==-1)  
  11.     {  
  12.         perror("semctl");  
  13.     }  
  14.     printf("Pemission Mode were %o\n", semopts.buf->sem_perm.mode);  
  15.     return;  
  16.   
  17. }  

实例: 

C代码  收藏代码
  1. semtool.c  
  2.   
  3. #include <stdio.h>  
  4. #include <ctype.h>  
  5. #include <stdlib.h>  
  6. #include <sys/types.h>  
  7. #include <sys/ipc.h>  
  8. #include <sys/sem.h>  
  9.   
  10. #define SEM_RESOURCE_MAX 1      /*Initial value of all semaphores*/  
  11.   
  12. void opensem(int *sid, key_t key);  
  13. void createsem(int *sid, key_t key, int members);  
  14. void locksem(int sid, int member);  
  15. void unlocksem(int sid, int member);  
  16. void removesem(int sid);  
  17. unsigned short get_member_count(int sid);  
  18. int  getval(int sid, int member);  
  19. void dispval(int sid,int member);  
  20. void changemode(int sid, char *mode);  
  21. void usage(void);  
  22.   
  23. int main(int argc, char *argv[])  
  24. {  
  25.     key_t key;  
  26.     int semset_id;  
  27.     if(argc == 1) usage();  
  28.   
  29.     /*Create unique key via call to ftok()*/  
  30.     key=ftok(".",'s');    
  31.     switch(tolower(argv[1][0]))  
  32.         {  
  33.   
  34.         case 'c':   
  35.         if(argc!=3)usage();  
  36.         createsem(&semset_id, key, atoi(argv[2]));  
  37.         break;  
  38.   
  39.         case 'l':  
  40.         if(argc!=3) usage();  
  41.         opensem(&semset_id, key);  
  42.         locksem(semset_id, atoi(argv[2]));  
  43.         break;  
  44.           
  45.         case 'u':  
  46.         if(argc!=3) usage();  
  47.         opensem(&semset_id, key);  
  48.         unlocksem(semset_id, atoi(argv[2]));  
  49.         break;  
  50.   
  51.         case 'd':   
  52.         opensem(&semset_id,key);  
  53.         removesem(semset_id);  
  54.         break;  
  55.   
  56.         case 'm':  
  57.         opensem(&semset_id, key);  
  58.         changemode(semset_id, argv[2]);  
  59.         break;  
  60.   
  61.         default:  
  62.         usage();  
  63.   
  64.   
  65.     }  
  66.     return(0);  
  67.   
  68. }  
  69.   
  70. void opensem(int *sid,  key_t key)  
  71. {  
  72.     /*Open the semaphore set ---do not creat!*/  
  73.     if((*sid=semget(key, 0 , 0666)==-1)  
  74.     {  
  75.   
  76.         printf("Semaphore set does not exist!\n");  
  77.         exit(1);  
  78.     }  
  79.   
  80. }  
  81.   
  82. void createsem(int *sid, key_t key, int members)  
  83. {  
  84.     int cntr;  
  85.     union semun semopts;  
  86.     if(members > SEMMSL){  
  87.         printf("Sorry,max number of semaphores in a set is %d\n",SEMMSL);  
  88.         exit(1);  
  89.   
  90.     }  
  91.     printf("Attempting to create new semaphore set with %d members\n",members);  
  92.     if((*sid=semget(key, members, IPC_CREAT|IPC_EXCL|0666))==-1)  
  93.     {  
  94.         fprintf(stderr,"Semaphore set already exist!\n");  
  95.         exit(1);  
  96.   
  97.     }  
  98.       
  99.     semopts.val= SEM_RESOURCE_MAX;  
  100.     /*Initialize all members(could be done with SETALL)*/  
  101.     for(cntr=0;cntr<members;cntr++)  
  102.     {  
  103.         semctl(*sid, cntr, SETVAL, semopts);  
  104.     }  
  105.   
  106. }  
  107.   
  108.   
  109. void locksem(int sid, int member)  
  110. {  
  111.     struct sembuf sem_lock={0, -1, IPC_NOWAIT};  
  112.     if(member <0 ||member>(get_member_count(sid) -1))  
  113.     {  
  114.         fprintf(stderr,"semaphore member %d out of range\n", member);  
  115.         return;  
  116.           
  117.   
  118.     }  
  119.       
  120.     /*Attempt to lock the semphore set*/  
  121.         if(!getval(sid, member))  
  122.     {  
  123.         fprintf(stderr,"Semaphore resources exhausted (no lock)\n")  
  124.         exit(1);      
  125.     }  
  126.   
  127.     sem_lock.sem_num =member;  
  128.       
  129.     if((semop(sid, &sem_lock, 1)==-1)  
  130.     {  
  131.         fprintf, "Lock faild\n");  
  132.             exit(1);  
  133.   
  134.   
  135.     }  
  136.     else  
  137.   
  138.         printf("Semaphore resources decremented by one (locked)\n");  
  139.     dispval(sid ,member);  
  140.   
  141.   
  142. }  
  143.   
  144.   
  145. void unlocksem(int sid, int member)  
  146. {  
  147.   
  148.     struct sembuf sem_unlock={member, 1, IPC_NOWAIT};  
  149.     int semval;  
  150.         if(member<0 || member>(get_member_count(sid)-1))  
  151.     {  
  152.         fprintf(stderr,"Semaphore member %d out of range\n",member);  
  153.         return;  
  154.   
  155.     }  
  156.   
  157.     /*Is the semaphore set locked? */  
  158.   
  159.     semval =getval(sid, member);  
  160.     if(semval==SEM_REOURSE_MAX){  
  161.   
  162.         fprintf(stderr, "Semaphore not locked!\n");  
  163.         exit(1);   
  164.   
  165.     }  
  166.   
  167.     sem_unlock.sem_num = member;  
  168.   
  169.     /*Attempt to lock the semaphore set*/  
  170.         if((semop(sid, &sem_unlock, 1))==-1)  
  171.     {  
  172.         fprintf(stderr, "Unlock failed\n");  
  173.         exit  
  174.   
  175.     }  
  176.     else  
  177.         printf("Semaphore resources incremented by one(unlocked)\n");  
  178.         dispval(sid, member);  
  179.   
  180.   
  181. }  
  182.   
  183.   
  184. void removesem(int sid)  
  185. {  
  186.     semctl(sid, 0, IPC_RMID,0);  
  187.     print("Semaphore removed\n");  
  188.   
  189. }  
  190.   
  191. unsigned short get_member_count(int sid)  
  192. {  
  193.   
  194.     union  semum semopts;  
  195.     struct semid_ds mysemds;  
  196.       
  197.     semopts.buf= &mysemds;  
  198.     /*Return number of member in the semaphore set*/  
  199.     int rc;  
  200.     if((rc=semctl(sid, 0, IPC_STAT, semopts))==-1)  
  201.     {  
  202.         perror("semctl");  
  203.         return(-1)  
  204.     }  
  205.       
  206.     return(semopts.buf->sem_nsems);  
  207.   
  208. }  
  209.   
  210. int getval(int sid, int member)  
  211. {  
  212.     int semval;  
  213.     semval= semctl(sid, member,GETVAL, 0)  
  214.     reval semval;  
  215.   
  216. }  
  217.   
  218. void changemode(int sid, char *mode)  
  219. {  
  220.     int rc;  
  221.     union semun semopts;  
  222.     struct semid_ds mysemds;  
  223.       
  224.     /*Get current values for internal data structure */  
  225.   
  226.     semopts.buf=&mysemds;  
  227.     rc = semctl(sid, 0, IPC_STAT, semopts);  
  228.     if(rc ==-1)  
  229.     {  
  230.         perror("semctl");  
  231.         exit(1);  
  232.   
  233.     }  
  234.   
  235.     printf("Old permission were %o\n", semopts.buf->perm.mode);  
  236.   
  237.     /* Change the permission on the semaphore */  
  238.     sscanf(mode,"%ho",&semopts.buf->sem_perm.mode);  
  239.   
  240.     /*Update the internal data structure */  
  241.     semctl(sid,0, IPC_SET, semopts);  
  242.       
  243.     printf("Updated......\n");  
  244.   
  245.   
  246. }  
  247.   
  248. void dispval(int sid, int member)  
  249. {  
  250.     int semval;  
  251.     semval= semctl(sid, member, GETVAL,0);  
  252.     printf("semval for member %d is %d\n", member ,semval);  
  253.   
  254.   
  255.   
  256. }  
  257.   
  258.   
  259.   
  260. void usage(void)  
  261. {  
  262.     fprintf(stderr, "semtool -Autility for thinking with semaphores\n");  
  263.     fprintf(stderr, "\nUSAGE:  semtool (c)reate <semcount>\n");  
  264.     fprintf(stderr, "                  (l)ock <sem #>\n");  
  265.         fprintf(stderr, "                  (u)nlock <sem #>\n");  
  266.     fprintf(stderr, "                  (d)elete\n");  
  267.     fprintf(stderr, "                  (m)ode <mode>\n");  
  268.     exit(1);  
  269.   
  270. }  

原创粉丝点击