进程通讯-信号量

有关结构体
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. }  
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值