进程同步实验 ipcs -*ipcs -mlinux中可用命令ipcs -m 观察共享内存 情况
key 共享内存关键值
shmid 共享内存标识
owner 共享内存所由者
perm 共享内存使用权限
byte 共享内存字节数
nattch 共享内存使用计数
status 共享内存状态
ipcs -slinux中可用命令ipcs -s 观察信号量数组 的情况
semid 信号量的标识号
nsems 信号量的个数
ipcs -qlinux中可用命令ipcs -q 观察消息队列 的情况。
msgmid 消息队列的标识号used-bytes 消息的字节长度messages 消息队列中的消息条数ipcrm在权限允许的情况下您可以使用ipcrm命令删除系统当前存在的IPC 对象中的任一个对象。
ipcrm -m 21482: 删除标号为21482 的共享内存。
ipcrm -s 32673: 删除标号为32673 的信号量数组。
ipcrm -q 18465: 删除标号为18465 的消息队列。
系统调用 IPC 对象有关的系统调用函数原型都声明在以下的头文件中 :
1 2 #include  <sys/types.h>  #include  <sys/ipc.h>  
其余参见指导书
共享内存 创建 创建一段共享内存系统调用语法 :
1 2 #include  <sys/shm.h>  int  shmget (key_t  key,int  size,int  flags) ;
key 共享内存的键值,可以为IPC_PRIVATE,也可以用整数指定一个
size 共享内存字节长度
flags 共享内存权限位。
shmget 调用成功后,如果key 用新整数指定,且flags 中设置了IPC_CREAT位,则返回一个新建立的共享内存段标识符。 如果指定的key 已存在则返回与key关联的标识符。 不成功返回-1
附加 令一段共享内存附加到调用进程中的系统调用语法:
1 2 #include  <sys/shm.h>  char  *shmat (int  shmid, char  *shmaddr,int  flags) 
shmid 由shmget创建的共享内存的标识符
shmaddr 总为0,表示用调用者指定的指针指向共享段
flags 共享内存权限位
shmat调用成功后返回附加的共享内存首地址
分离 令一段共享内存从到调用进程中分离出去的系统调用语法:
1 2 #include  <sys/shm.h>  int  shmdt (char  *shmadr) ;
shmadr 进程中指向附加共享内存的指针
shmdt 调用成功将递减附加计数,当计数为0,将删除共享内存。调用不成功返回-1。
信号量 创建 创建一个信号量数组的系统调用有语法:
1 2 #include  <sys/sem.h>  int  semget (key_t  key,int  nsems, int  flags) ;
key 信号量数组的键值,可以为IPC_PRIVATE,也可以用整数指定一个
nsems 信号量数组中信号量的个数
flags 信号量数组权限位。如果key用整数指定,应设置IPC_CREAT 位。
semget调用成功,如果key用新整数指定,且flags 中设置了IPC_CREAT 位,则返回一个新建立的信号等数组标识符。 如果指定的整数key已存在则返回与key关联的标识符。 不成功返回-1
操作 操作信号量数组的系统调用语法:
1 2 #include  <sys/sem.h>  int  semop (int  semid,struct  sembuf *semop, unsigned  nops) ;
semid 由semget创建的信号量数组的标识符
semop 指向sembuf数据结构的指针
nops 信号量上的操作数,例如该值为1 相当于P操作,-1 相当于V操作.
semop调用成功返回0,不成功返回-1。
控制 控制信号量数组的系统调用语法:
1 2 #include  <sys/sem.h>  int  semctl (int  semid,int  semnum,int  cmd, union  semun arg) ;
semid 由semget创建的信号量数组的标识符
semnum 该信号量数组中的第几个信号量
cmd 对信号量发出的控制命令。例如:
GETVAL 返回当前信号量状态
SETVAL 设置信号量状态
IPC_RMD 删除标号为semid的信号量
arg 保存信号量状态的联合体,信号量的值是其中一个基本成员
1 2 3 4 union  semun  {int  val; ...... }; 
semctl 执行不成功返回-1,否则返回指定的cmd的值。
semget() semget()函数既可以用于获取之前创建的信号量集合,也可以用于创建新的信号量集合。semget()的函数原型如下:
1 2 int  semget (key_t  key, int  nsems, int  semflg) ;
key是绑定在信号量集合上的,我们可以用key来寻找已经创建的信号量集合,或者用于创建并绑定新的信号量集合。注意,key和函数的返回值(信号量集合)不是一样的。nsems表示该信号量集合有多少个信号量,如果用信号量来创建binary semaphore,我们只需要将nsems设置为1。semflg是设置信号量集合的标志位,其中最低9位是信号量集合的访问权限(和文件一样,3个8进制数字,比如0777)。其他位和文件创建的标志位类似,比如IPC_CREAT是创建新的信号量集合(文件是O_CREAT),在使用信号量前,我们都需要创建信号量集合。
在调用该系统调用后,与信号量集合绑定的数据结构semid_ds也被初始化。
semop() semop()用于操作信号量,简单来说就是对信号量的计数器进行加减。函数原型如下:
1 int  semop (int  semid, struct  sembuf *sops, size_t  nsops) ;
semid是信号量集合的标识符,注意,这不是semget()中的key而是这个函数的返回值。nsops是有多少个信号量需要被操作,在我们的例子中只有1个信号量需要被操作。sops是对信号量操作的具体命令,它是一个struct sembuf类型的结构体,一共有nsops个这样的结构体:
1 2 3 unsigned  short  sem_num;  short           sem_op;   short           sem_flg;  
sem_num是从0开始计数的,表示是第几个信号量;sem_flg可以选择IPC_NOWAIT和SEM_UNDO,SEM_UNDO表示在进程结束后,内核会自动释放没有主动释放的信号量。sops是按照数组的顺序执行的,并且是原子的,如果所有的信号量不能同时操作,那么就不进行操作。
sem_op的使用很简单,但具体如何设置、不同设置有什么不同却比较麻烦。在binary semaphore的例子中,sem_op设置为1就是信号量计数器加1;设置为-1就是信号量计数器减1,下面具体讲讲sem_op设置背后的故事。
除了上面提到的sembuf结构体,每个信号量还对应一系列变量:
1 2 3 4 unsigned  short   semval;   unsigned  short   semzcnt;  unsigned  short   semncnt;  pid_t            sempid;   
之前提到的信号量计数器就是semval,semzcnt是等待semval为0的进程数,semncnt是等待semval增加的进程数。semop()对信号量的操作都会改变这些变量。
如果sem_op设置为正数,那么每次操作后semval将变成semval + sem_op;如果sem_flg设置了SEM_UNDO,那么semadj将变成semadj - sem_op。进程需要有写的权限才能修改信号量。
如果sem_op设置为负数,情况要复杂些:
如果abs(sem_op)小于等于semval,那么semval将变成semval - abs(sem_op);如果sem_flg设置了SEM_UNDO,那么semadj将变成semadj + abs(sem_op); 如果abs(sem_op)大于semval并且sem_flg设置了IPC_NOWAIT,那么将返回错误码EAGAIN,并且sem_op的操作不会进行; 如果2中没有设置IPC_NOWAIT,那么semval将变成semval - abs(sem_op),同时semncnt 变成semncnt + 1,并且进程会进入sleep状态。当semval >= abs(sem_op)时,进程会被唤醒。 其他具体细节请参考man semop 。
从加锁和解锁的角度进行思考,当semval = 0时,如果操作是sem_op = -1,那么semval将变成-1,因此进程进入睡眠状态:这就是加锁的操作;同理,sem_op = 1是解锁的操作。
semctl() 通过上面两个系统调用,我们知道如何创建信号量以及如何操作信号量,下面这个系统调用可以初始化信号量以及删除信号量。我们先来看看semctl()的函数原型:
1 int  semctl (int  semid, int  semnum, int  cmd, ...) ;
semctl()支持的命令有很多,这里我们主要介绍两个 - IPC_RMID和SETVAL。semid是信号量集合的索引,semnum是其中第几个信号量(从0开始),cmd就是命令。这个函数是可变长度参数,有些命令是4个参数,第4个参数是union semun,这个union定义如下,注释中注明了哪些命令要用这个union:
1 2 3 4 5 6 union  semun  {    int               val;         struct  semid_ds  *buf ;     unsigned  short   *array ;       struct  seminfo   *__buf ; }; 
使用SETVAL命令时,我们就是通过val给semval赋值,用于初始化信号量。我们这里看看如何使用semctl()来初始化和删除信号量:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 int  set_sem (int  sem_id)  {    union  semun  sem_union ;     sem_union.val = 1 ;       if (semctl(sem_id, 0 , SETVAL, sem_union) == -1 ) {          fprintf (stderr , "Failed to set sem\n" );           return  0 ;       }     return  1 ;   } void  del_sem (int  sem_id)  {      union  semun  sem_union ;     if (semctl(sem_id, 0 , IPC_RMID, sem_union) == -1 )           fprintf (stderr , "Failed to delete sem, sem has been del.\n" );   } 
参考:https://rdou.github.io/2020/06/22/Linux编程基础3-进程间通信-信号量/ 
基本逻辑 生产者:首先如果缓冲区满则生产者阻塞,其次生产者不能同时进行提供材料,所以要设置互斥锁使其不能同时进行执行。生产者每次提供其中的两种后,唤醒抽烟者。
抽烟者:而对于抽烟者来说,刚开始并没有所需要的材料,要等待生产者的唤醒,同时还要设置互斥锁防止抽烟者同时进行吸烟。判断当前放的两个材料是否是其所需,是则从共享缓冲区间读取所需要的数据,然后唤起两个生产者和其他抽烟者。若不是,则唤醒其他抽烟者抽烟。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 semaphore tobacco_paper     = 0 ;  semaphore tobacco_matches   = 0 ;  semaphore paper_matches     = 0 ;  semaphore doneSomking       = 0 ; while ( true  ) {	 pick a random number from 1 -3  	 if  random number is 1                   signal( tobacco_paper ) 	 else  if  random number is 2                     signal( tobacco_matches )   	 else  if  random number is 3                    signal( paper_matches )        wait( doneSmoking ) }  while (true ){   wait( tobacco_paper );         signal( doneSmoking ); } while (true ){   wait(tobacco_matches);         signal( doneSmoking ); } while (true ){   wait(matches_paper );         signal( doneSmoking ); } 
Linux下的代码设计 参考 
①关系分析:供应者与三个抽烟者分别是同步关系。由于抽烟者无法同时满足两个或以上的抽烟者,三个抽烟者对抽烟这个动作互斥(或由三个抽烟者轮流抽烟得知)。
②整体思路:一共设计六个文件,ipc.h和ipc.c设计信号量机制实现的底层逻辑,例如消息队列、P操作、V操作等。设计四个进程,供应者作为生产者向三个抽烟者提供材料。
③信号量设置:信号量offer1、offer2、offer3分别表示烟草和纸组合,烟草和胶水组合,胶水和纸组合。信号量finish表示抽烟完成信号。它们之间的协同关系如下图:
同时还要设置一个互斥信号量 ,保证4个进程互斥访问缓冲区,但该互斥信号量不是必须的,因为本例中缓冲区大小只为1。
代码 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 #include  <stdio.h>  #include  <stdlib.h>  #include  <sys/types.h>  #include  <unistd.h>  #include  <sys/ipc.h>  #include  <sys/shm.h>  #include  <sys/sem.h>  #include  <sys/msg.h>  #define  BUFSZ 256 int  get_ipc_id (char  *proc_file,key_t  key) ;char  *set_shm (key_t  shm_key,int  shm_num,int  shm_flag) ;int  set_msq (key_t  msq_key,int  msq_flag) ;int  set_sem (key_t  sem_key,int  sem_val,int  sem_flag) ;int  down (int  sem_id) ;int  up (int  sem_id) ;typedef  union  semuns {     int  val; } Sem_uns; typedef  struct  msgbuf {     long  mtype;     char  mtext[1 ]; } Msg_buf; key_t  buff_key;int  buff_num;char  *buff_ptr;key_t  pput_key;int  pput_num;int  *pput_ptr;key_t  cget_key;int  cget_num;int  *cget_ptr;key_t  offer1_key;key_t  offer2_key;key_t  offer3_key;key_t  finish_key;key_t  mutex_key;int  offer1;int  offer2;int  offer3;int  finish;int  mutex;int  sem_val;int  sem_flg;int  shm_flg;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 #include  "ipc.h"  int  get_ipc_id (char  *proc_file, key_t  key)  {     FILE *pf;     int  i,j;     char  line[BUFSZ], colum[BUFSZ];     if ((pf = fopen(proc_file,"r" )) == NULL )     {         perror("Proc file not open" );         exit (EXIT_FAILURE);     }          fgets(line, BUFSZ, pf);         while (!feof(pf))     {         i = j = 0 ;         fgets(line, BUFSZ,pf);         while (line[i] == ' ' )              i++;         while (line[i] != ' ' )             colum[j++] = line[i++];         colum[j] = '\0' ;                  if (atoi(colum) != key)                 continue ;                  j = 0 ;         while (line[i] == ' ' )             i++;         while (line[i] !=' ' )             colum[j++] = line[i++];         colum[j] = '\0' ;         i = atoi(colum);         fclose(pf);                  return  i;     }     fclose(pf);     return  -1 ; } int  down (int  sem_id)  {     struct  sembuf  buf ;          buf.sem_num = 0 ;          buf.sem_op = -1 ;          buf.sem_flg = SEM_UNDO;          if ((semop(sem_id,&buf,1 )) < 0 )      {         perror("P error " );         exit (EXIT_FAILURE);     }     return  EXIT_SUCCESS; } int  up (int  sem_id)  {     struct  sembuf  buf ;     buf.sem_op = 1 ;     buf.sem_num = 0 ;     buf.sem_flg = SEM_UNDO;     if ((semop(sem_id,&buf,1 )) < 0 )      {         perror("V error " );         exit (EXIT_FAILURE);     }     return  EXIT_SUCCESS; } int  set_sem (key_t  sem_key, int  sem_val, int  sem_flg)  {     int  sem_id;            Sem_uns sem_arg;          if ((sem_id = get_ipc_id("/proc/sysvipc/sem" , sem_key)) < 0  )     {                  if ((sem_id = semget(sem_key, 1 , sem_flg)) < 0 )         {             perror("semaphore create error" );             exit (EXIT_FAILURE);         }                  sem_arg.val = sem_val;                           if (semctl(sem_id, 0 , SETVAL, sem_arg) < 0 )         {             perror("semaphore set error" );             exit (EXIT_FAILURE);         }     }    return  sem_id; } char * set_shm (key_t  shm_key, int  shm_num, int  shm_flg)  {     int  i, shm_id;          char * shm_buf;          if ((shm_id = get_ipc_id("/proc/sysvipc/shm" , shm_key)) < 0  )     {                  if ((shm_id = shmget(shm_key, shm_num, shm_flg)) < 0 )         {             perror("shareMemory set error" );             exit (EXIT_FAILURE);         }                  if ((shm_buf = (char *)shmat(shm_id, 0 , 0 )) < (char  *)0 )         {             perror("get shareMemory error" );             exit (EXIT_FAILURE);         }                  for (i = 0 ; i < shm_num; i++)              shm_buf[i] = 0 ;     }               if ((shm_buf = (char *)shmat(shm_id, 0 , 0 )) < (char *)0 )     {         perror("get shareMemory error" );         exit (EXIT_FAILURE);     }     return  shm_buf; } int  set_msq (key_t  msq_key,int  msq_flg) {     int  msq_id;          if ((msq_id = get_ipc_id("/proc/sysvipc/msg" , msq_key)) < 0  )     {                  if ((msq_id = msgget(msq_key,msq_flg)) < 0 )         {             perror("messageQueue set error" );             exit (EXIT_FAILURE);         }     }     return  msq_id; } 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 #include  "ipc.h"  #include <stdlib.h>  int  main (int  argc,char  *argv[]) {     int  rate;          if (argv[1 ] != NULL )         rate = atoi(argv[1 ]);     else          rate = 1 ;             buff_key = 101 ;      buff_num = 1 ;        pput_key = 102 ;      pput_num = 1 ;             shm_flg = IPC_CREAT | 0644 ;          buff_ptr = (char *)set_shm(buff_key, buff_num, shm_flg);          pput_ptr = (int *)set_shm(pput_key, pput_num, shm_flg);          offer1_key = 201 ;     offer2_key = 202 ;     offer3_key = 203 ;     finish_key = 204 ;     mutex_key = 205 ;           sem_flg = IPC_CREAT | 0644 ;          sem_val = 0 ;     offer1 = set_sem(offer1_key, sem_val, sem_flg);     offer2 = set_sem(offer2_key, sem_val, sem_flg);     offer3 = set_sem(offer3_key, sem_val, sem_flg);     finish = set_sem(finish_key, sem_val, sem_flg);          sem_val = 1 ;     mutex = set_sem(mutex_key, sem_val, sem_flg);          int  i = 0 ;     while (1 )     {         i = (i + 1 ) % 3 ;         buff_ptr[*pput_ptr] = i + 1 ;         sleep(rate);         down(mutex);         	    *pput_ptr = (*pput_ptr + 1 ) % buff_num;         if (i == 0 ) {             printf ("%d put offer1 - tobacco and paper into buffer[%d]\n" , getpid(), *pput_ptr);             up(offer1);              }         else  if (i == 1 ) {             printf ("%d put offer2 - glue and tobacco into buffer[%d]\n" , getpid(), *pput_ptr);             up(offer2);              }         else  {             printf ("%d put offer3 - glue and paper into buffer[%d]\n" , getpid(), *pput_ptr);             up(offer3);              }         up(mutex);                 down(finish);              }     return  EXIT_SUCCESS; } 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 #include  "ipc.h"  int  main (int  argc,char  *argv[]) {     int  rate;          if (argv[1 ] != NULL )         rate = atoi(argv[1 ]);     else          rate = 3 ;               buff_key = 101 ;      buff_num = 1 ;        cget_key = 103 ;      cget_num = 1 ;        shm_flg = IPC_CREAT | 0644 ;          buff_ptr = (char *)set_shm(buff_key, buff_num, shm_flg);          cget_ptr = (int *)set_shm(cget_key, cget_num, shm_flg);          offer1_key = 201 ;     offer2_key = 202 ;     offer3_key = 203 ;     finish_key = 204 ;     mutex_key = 205 ;           sem_flg = IPC_CREAT | 0644 ;          sem_val = 0 ;     offer3 = set_sem(offer3_key, sem_val, sem_flg);     finish = set_sem(finish_key, sem_val, sem_flg);          sem_val = 1 ;     mutex = set_sem(mutex_key, sem_val, sem_flg);     while (1 )     {         sleep(rate);         down(offer3);         down(mutex);         *cget_ptr = (*cget_ptr + 1 ) % buff_num;         printf ("%d smoker get glue and paper offer%d from buffer[%d]\n" , getpid(), buff_ptr[*cget_ptr], *cget_ptr);         up(mutex);                  up(finish);     }     return  EXIT_SUCCESS; } 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 #include  "ipc.h"  int  main (int  argc,char  *argv[]) {     int  rate;          if (argv[1 ] != NULL )         rate = atoi(argv[1 ]);     else          rate = 3 ;               buff_key = 101 ;      buff_num = 1 ;        cget_key = 103 ;      cget_num = 1 ;        shm_flg = IPC_CREAT | 0644 ;          buff_ptr = (char *)set_shm(buff_key, buff_num, shm_flg);          cget_ptr = (int *)set_shm(cget_key, cget_num, shm_flg);          offer1_key = 201 ;     offer2_key = 202 ;     offer3_key = 203 ;     finish_key = 204 ;     mutex_key = 205 ;           sem_flg = IPC_CREAT | 0644 ;          sem_val = 0 ;     offer2 = set_sem(offer2_key, sem_val, sem_flg);     finish = set_sem(finish_key, sem_val, sem_flg);          sem_val = 1 ;     mutex = set_sem(mutex_key, sem_val, sem_flg);     while (1 )     {         sleep(rate);         down(offer2);         down(mutex);         *cget_ptr = (*cget_ptr + 1 ) % buff_num;         printf ("%d smoker get glue and tobacco offer%d from buffer[%d]\n" , getpid(), buff_ptr[*cget_ptr], *cget_ptr);         up(mutex);                  up(finish);     }     return  EXIT_SUCCESS; } 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 #include  "ipc.h"  int  main (int  argc,char  *argv[]) {     int  rate;     if (argv[1 ] != NULL )         rate = atoi(argv[1 ]);     else          rate = 3 ;          buff_key = 101 ;      buff_num = 1 ;        cget_key = 103 ;      cget_num = 1 ;        shm_flg = IPC_CREAT | 0644 ;          buff_ptr = (char *)set_shm(buff_key, buff_num, shm_flg);          cget_ptr = (int *)set_shm(cget_key, cget_num, shm_flg);          offer1_key = 201 ;     offer2_key = 202 ;     offer3_key = 203 ;     finish_key = 204 ;     mutex_key = 205 ;           sem_flg = IPC_CREAT | 0644 ;          sem_val = 0 ;     offer1 = set_sem(offer1_key, sem_val, sem_flg);     finish = set_sem(finish_key, sem_val, sem_flg);          sem_val = 1 ;     mutex = set_sem(mutex_key, sem_val, sem_flg);          while (1 )     {         sleep(rate);         down(offer1);         down(mutex);         *cget_ptr = (*cget_ptr + 1 ) % buff_num;         printf ("%d smoker get tobacco and paper offer%d from buffer[%d]\n" , getpid(), buff_ptr[*cget_ptr], *cget_ptr);         up(mutex);                  up(finish);     }          return  EXIT_SUCCESS; } 
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 hdrs = ipc.h opts = -g -c  p_src = producer.c ipc.c p_obj = producer.o ipc.o c_T_src = consumer_tobacco.c ipc.c c_T_obj = consumer_tobacco.o ipc.o c_P_src = consumer_paper.c ipc.c c_P_obj = consumer_paper.o ipc.o c_G_src = consumer_glue.c ipc.c c_G_obj = consumer_glue.o ipc.o all: producer consumer_tobacco consumer_paper consumer_glue producer: $(p_obj)  	gcc $(p_obj)  -o producer producer.o: $(p_src)  $(hdrs)  	gcc $(opts)  $(p_src)  consumer_tobacco: $(c_T_obj)  	gcc $(c_T_obj)  -o consumer_tobacco consumer_tobacco.o: $(c_T_src)  $(hdrs)  	gcc $(opts)  $(c_T_src)  consumer_paper: $(c_P_obj)  	gcc $(c_P_obj)  -o consumer_paper consumer_paper.o: $(c_P_src)  $(hdrs)  	gcc $(opts)  $(c_P_src)  consumer_glue: $(c_G_obj)  	gcc $(c_G_obj)  -o consumer_glue consumer_glue.o: $(c_G_src)  $(hdrs)  	gcc $(opts)  $(c_G_src)  clean:  	rm producer consumer_tobacco consumer_paper consumer_glue *.o 
一些问题 由于该程序会修改文件/proc/sysvipc/sem中的记录,且运行完后不会删除,因此如果多次对文件进行修改,并make后执行,可能使用到一个错误的信号量id,对该信号量的操作不会反映到程序中,程序会直接跳过对信号量的P操作和V操作。解决方法是重启虚拟机。 比如,就会这样:
finish同步信号量的设置可以为1或0,如果是1,则应该在while循环开始处调用P操作,这样第一遍循环可以顺利执行,阻塞在第二次循坏的开始处;如果是0,则阻塞在while循坏的尾部。