【详解】进程间通信之信号量

临界资源:具有排他性的资源

临界区:访问临界资源的代码段

信号量的本质就是计数器

互斥访问 

操作系统的P操作就是上锁,V操作就是解锁

上锁()                                                    解锁()

  {                                                               {

       计数器--                                                    计数器++

       if(计数器<0)                                              if(计数器<=)

      {                                                                {

            进入阻塞状态                                             唤醒阻塞队列

            放入阻塞队列                                           }

      }                                                             }

举个例子:

我们常见的购票就可以理解为互斥,当用户1和用户2都有购票需求时,假设用户1先访问购票系统,如果没有互斥锁,用户1运行if(票数>0)发现还有一张票果断下单购买,这时用户1进程运行的时间片到了,切换到用户2,用户2运行if(票数>0)由于票数还没来得及--,此时还显示着票数为1,这样就会导致用户1与2都买了同一张票,这显然是不行的。这就要求我们上锁,在用户1购买的时候加锁,哪怕时间片到了切换到用户2,由于锁的限制用户2无法访问,也就无法购买了。那么我们如何控制互斥锁呢?这里就要引出信号量。这里让信号量为1,每次P申请锁,信号量--,每次V释放锁,信号量++。图示如下

进程同步:

标准概念:进程同步也是进程之间直接的制约关系,是为完成某种任务而建立的两个或多个线程,这个线程需要在某些位置上协调他们的工作次序而等待、传递信息所产生的制约关系。进程间的直接制约关系来源于他们之间的合作。

举个例子:

我们常见的司机与售票员之间的故事:当乘客们已经顺利登车,司机要开门必须要等售票员关好门才可以,同理售票员要开门必须要等司机到站停车才可以。这两者之间的关系就是同步。示例如图:

创建或打开信号量:

int semget(key_t key,int nsems,int flags)

nsems:信号量集中信号量的个数

flags:打开 0

            创建IPC_CREAT|0644 

具体代码:

  1 #include<stdio.h>
  2 #include<stdlib.h>
  3 #include<sys/ipc.h>
  4 #include<sys/sem.h>
  5 int main()
  6 {
  7     int id=semget(123,1,IPC_CREAT|0644);
  8     if(id==-1)
  9     {
 10         perror("id");
 11         exit(1);
 12     }
 13     printf("semget success!\n");                                            
 14 }

验证是否创建成功:

这里的nsems表示信号量集中有多少个信号量

设置信号量初值:

semctl(int semid,int semnum,int cmd,su);

semnum:信号量集中的第几个信号量

cmd:命令,这里用SETVAL

union semun{

          int  val;//设定信号量的值

具体代码:

  1 #include<stdio.h>
  2 #include<sys/ipc.h>
  3 #include<sys/sem.h>
  4 #include<stdlib.h>
  5 union semun{
  6     int val;
  7 };
  8 int main()
  9 {
 10     int id=semget(123,0,0);
 11     if(id==-1)
 12     {
 13         perror("id");
 14         exit(1);
 15     }
 16     union semun su;
 17     su.val=5;
 18     semctl(id,0,SETVAL,su);                                                 
 19 }

查看信号量的值:

int semctl(int semid,int semnum,int cmd,0)

semnum:信号量集中的第几个信号量

cmd:命令,这里为GETVAL 

0:无需再重复定义联合体

返回值为当前信号量的值

具体代码:

  1 #include<stdio.h>
  2 #include<sys/ipc.h>
  3 #include<sys/sem.h>
  4 #include<stdlib.h>
  5 int main()
  6 {
  7     int id=semget(123,0,0);
  8     if(id==-1)
  9     {
 10         perror("id");
 11         exit(1);
 12     }
 13     int val=semctl(id,0,GETVAL,0);
 14     printf("val=%d",val);                                                   
 15 
 16 }

PV操作:

semop (int id,struct sembuf sb[],int len)

len:数组的长度

struct sembuf{

      short sem_num,  //信号量的下标

      short sem_op,     // 1表示V操作,-1表示P操作

      short  sem_flg   //一般填0,表示如果信号量为0就阻塞

};

P操作具体代码:

  1 #include<stdio.h>
  2 #include<stdlib.h>
  3 #include<sys/ipc.h>
  4 #include<sys/sem.h>
  5 void p(int id)
  6 {
  7     struct sembuf sb[1];
  8     sb[0].sem_num=0;
  9     sb[0].sem_op=-1;
 10     sb[0].sem_flg=0;
 11     semop(id,sb,1);
 12 }
 13 int main()
 14 {
 15     int id=semget(123,0,0);
 16     if(id==-1)
 17     {
 18         perror("semget");
 19         exit(1);
 20     }
 21     p(id);                                                                  
 22 }

V操作具体代码:

  1 #include<stdio.h>
  2 #include<stdlib.h>
  3 #include<sys/ipc.h>
  4 #include<sys/sem.h>
  5 v(int id)
  6 {
  7     struct sembuf sb[1];
  8     sb[0].sem_num=0;                                                        
  9     sb[0].sem_op=1;
 10     sb[0].sem_flg=0;
 11     semop(id, sb,1);
 12 }
 13 int main()
 14 {
 15     int id=semget(123,0,0);
 16     if(id==-1)
 17     {
 18         perror("semget");
 19     }
 20     v(id);
 21 
 22 }

猜你喜欢

转载自blog.csdn.net/enjoymyselflzz/article/details/81603577