5.4 SYSV进程通信之信号灯集

sem.c

  1 /*摘自:信号量(semaphore):主要作为进程间以及同一进程不同线程之间的同步手段。
  2  *         信号量:就是用来解决进程间的同步与互斥问题的一种进程间通信机制。
  3  *
  4  * 信号灯集:一组信号量的集合,信号灯进行两个进程同步的操作和信号量完成的功能是一样的,
  5  *             但两者操作方式标准不同:
  6  *         信号量(POSIX)
  7  *         信号灯(SYSV)
  8  *
  9  * PV原子操作的具体定义如下:(好好理解,很重要的啊)
 10  * P操作:如果有可用的资源(信号量值>0),则此操作所在的进程占用一个资源(此时信号量值减1,进入临界区代码);
 11  *         如果没有可用的资源(信号量值=0),则此操作所在的进程被阻塞直到系统将资源分配给该进程(进入等待队列,一直等到资源轮到该进程)。
 12  *
 13  * V操作:如果在该信号量的等待队列中有进程在等待资源,则唤醒一个阻塞进程;如果没有进程等待它,
 14  *         则释放一个资源(即信号量值加1)。
 15  */
 16 
 17 #include <stdio.h>
 18 #include <stdlib.h>
 19 #include <string.h>
 20 #include <error.h>
 21 #include <errno.h> 
 22 #include <sys/types.h>
 23 #include <sys/stat.h>
 24 #include <sys/ipc.h>
 25 #include <sys/sem.h>
 26 
 27 #define error_exit(_errmsg_) error(EXIT_FAILURE,errno,_errmsg_)
 28 
 29 #define w 0
 30 #define r 1
 31 
 32 union semun {
 33       int val;  /* Value for SETVAL */
 34       struct semid_ds *buf;  /* Buffer for IPC_STAT, IPC_SET */
 35       unsigned short  *array;  /* Array for GETALL, SETALL */
 36       struct seminfo  *__buf;  /* Buffer for IPC_INFO   (Linux-specific) */
 37         };
 38 
 39 /*初始化一个信号灯中所有的信号量*/
 40 int init_sem(int semid,int *array,int len)
 41 {
 42     union semun myun;
 43     int i = 0;
 44     for(i = 0;i < len;i++)
 45     {
 46         myun.val = array[i];
 47         if(-1 == (semctl(semid,i,SETVAL,myun)))
 48             error_exit("fail to semctl!");
 49     }
 50     return 0;
 51 }
 52 
 53     /* 操作一个信号量,让其完成申请/释放资源的操作
 54      * int semop(int semid, struct sembuf *sops, unsigned nsops);
 55      * semid:
 56      * struct sembuf *sops;对信号灯操作方式的集合
 57      * nsops: 信号量操作的个数
 58      * 成功返回0;失败返回-1.
 59      *
 60      * */
 61 
 62 //P操作:申请资源的操作
 63 int sem_p(int semid,int num,int n)
 64 {
 65     struct sembuf mybuf;
 66 
 67     mybuf.sem_num = num;
 68     mybuf.sem_op = -1;
 69     mybuf.sem_flg = SEM_UNDO;
 70     if(-1 == semop(semid,&mybuf,n))
 71             error_exit("fail to semop!");
 72     return 0;
 73 }
 74 
 75 //V操作:释放资源的操作
 76 int sem_v(int semid,int num,int n)
 77 {
 78     struct sembuf mybuf;
 79 
 80     mybuf.sem_num = num;
 81     mybuf.sem_op = +1;
 82     mybuf.sem_flg = SEM_UNDO;
 83     if(-1 == semop(semid,&mybuf,n))
 84             error_exit("fail to semop!");
 85     return 0;
 86 }
 87 
 88 
 89 int main(void)
 90 {
 91     key_t key;
 92     if(-1 == (key = ftok(".",'a')))
 93         error_exit("fail to ftok!");
 94     /*创建一信号灯
 95      *int semget(key_t key, int nsems, int semflg);
 96      *参数:
 97         key:键值
 98         nsem: 该信号灯中信号量的个数
 99         semflg:IPC_CREAT
100                 IPC_EXCL
101         成功返回信号灯的ID号,失败返回-1
102      * */
103     int semid = 0;
104     int a[2] = {1,0};
105 
106     if(-1 == (semid = semget(key,2,IPC_CREAT | 0644)))
107         error_exit("fail to semget!");
108 
109     /* 对信号灯中的信号量进行相应的操作/发命令
110      * int semctl(int semid, int semnum, int cmd, ...);
111      * 参数:
112      *         semid:信号灯ID号
113      *         semnum:信号灯中信号量的下标
114      *         cmd:    SETVAL: 设置信号灯中信号量的值
115      *                 IPC_RMID:删除信号灯
116      *                 IPC_SET:
117      *                 IPC_STAT:
118      * 成功返回0;失败返回-1.
119      */
120     init_sem(semid,a,2);
121 
122     sem_p(semid,w,1);
123     printf("申请到了写资源...\n");
124 
125     sem_v(semid,r,1);
126     printf("释放到了读资源...\n");
127     
128     sem_p(semid,r,1);
129     printf("申请到了读资源...\n");
130 
131     semctl(semid,0,IPC_RMID);
132     return 0;
133 }

 

posted @ 2017-03-14 21:36  bkycrmn  阅读(210)  评论(0)    收藏  举报