linux信号量实现进程间同步与互斥

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/weixin_40921797/article/details/82840119

什么是同步与互斥

同步与互斥是进程间的制约关系,
同步:
是为了保证临界资源的时序的可控性,安全性。是进程间由于相互合作引起的直接制约关系。
互斥:
是为了保证对临界资源同一时间的唯一访问性。是进程间由于共享资源引起的间接制约关系。
多个进程当需要操作同一资源的时候就需要通过同步和互斥机制来实现对临界资源的安全访问。

什么是临界资源

临界资源就是:一次只允许一个进程访问的资源。

什么是信号量

从本质上来讲信号量是一个有等待队列的计数器。这就很想我们去一件很火的餐厅吃饭,需要牌号等位一样。
从信号量的实现角度讲,信号量就是一个结构体类型的数据变量。是对系统中资源和其组织情况的抽象。
结构体中有两个成员:
value:当该值 >0 标志现在有几个空闲的可用资源,初值是一共有几个可用资源。
当 =0 标志资源整合用完
当 <0 该值的绝对值标志现在有几个等待该类资源的进程,对应着阻塞队列的长度。
L:阻塞队列,是等待该资源的进程pcb表链。该队列的长度对象value<0时的绝对值,此时在该队列的进程都处于阻塞状态。

信号量也是进程间通信的方式一种。也就是说信号量本事也是一个临界资源,为了保证其安全我们规定信号量的操作是原子操作,也就是说该操作不可被打断。要不不做,要不必须完成。

P-V操作

p操作:是申请资源的过程。
1.value的值自减减,使用的共有操作,所以复用写在前面:value–
2.系统判断value的值是否 >=0:
1).是>=0:表示有空闲可以访问,进入临界区访问临界资源。
2).否<0:表示没有空闲,则让权从执行转入阻塞状态,在阻塞队列中标记
V操作:是释放资源的过程。
1.value的值自加加:value++
2.系统判断value的值是否<=0:
1).否>0:此时没有多余进程阻塞等待。
2).是<=0:有进程等待,唤醒阻塞队列的第一个进程,使其由阻塞到就绪状态。
3.该进程可以继续执行访问剩余区(非临界区),若执行完,则让权释放cpu。

如何实现同步与互斥

同步:
由一个无条件执行的进程开始,信号量资源初始值为0,该进程结束进行V(S)操作,信号量资源+1,此时会通知别的进程。需要该资源的进程,打破阻塞,P(S)操作,去访问临界资源。
互斥:
P(S)操作,资源-1,则其余进程不可再访问该份临界资源。使用完V(S)操作,资源+1,此时别的进程才可进行是否可以访问判断。

操作信号量

1.创建信号量
system V标志的信号量,可以创建的时候创建一个集合及多个信号量

       #include <sys/types.h>
       #include <sys/ipc.h>
       #include <sys/sem.h>
       int semget(key_t key, int nsems, int semflg);
       //key值做信号量的标识,nsems指定一次创建多少个信号量
       //semflg 是创建权限,IPC_CREATE
       //返回文件标识符

2.设置信号量初值
信号量的初值只能设置一次。

 int semctl (int semid,int semnum,int cmd,...);
 //semid 操作句柄 semnum 指定要操作几个信号量,
 //cmd具体的操作(SETVAL设置单个信号量初值,SETALL设置所以信号量初值,semnum的值会被忽略)
 //... 不定参数,这里是一个结构体获取信号量信息,一个联合获取信号量的值 。
 union semun {
     int                          val;    /* Value for SETVAL */
      struct semid_ds *buf;    /* Buffer for IPC_STAT, IPC_SET */
      unsigned short  *array;  /* Array for GETALL, SETALL */
      struct seminfo  *__buf;  /* Buffer for IPC_INFO
                                                     (Linux-specific) */
 };

3.在对临界资源操作前,先获取信号量-1操作

//semid 句柄,  
//struct sembuf, containing the following members:           
// unsigned short sem_num;  /* 信号量集合中的信号量编号,0代表第1个信号量 */
//          short          sem_op;   
/*若op>0进行V操作信号量值加op,表示进程释放控制的资源*/
/*若op<0进行P操作信号量值减o'p*/
 //          short          sem_flg;  
/* 设置信号量的默认操作,IPC_NOWAIT设置信号量操作不等待*/
/*SEM_UNDO 选项会让内核记录一个与调用进程相关的UNDO记录,如果该进程崩溃,则根据这个进程的UNDO记录自动恢复相应信号量的计数值*/
    struct sembuf buf;
     buf.sem_num = 0; 
     buf.sem_op = -1;
     buf.sem_flg = SEM_UNDO;
     semop(id, &buf, 1);

4.对临界资源操作完成后,释放资源,信号量+1操作

//semid 句柄,  
//struct sembuf, containing the following members:            
//unsigned short sem_num;  /* semaphore number */
//          short          sem_op;   /* semaphore operation */
//         short          sem_flg;  /* operation flags */
    struct sembuf buf;
    buf.sem_num = 0;
    buf.sem_op = 1;
    buf.sem_flg = SEM_UNDO;
    semop(id, &buf, 1);

5.使用完信号量对其进行删除操作

 int semctl (int semid,int semnum,int cmd,...);
 //删除也是使用semctl只不过cmd的具体操作是IPC_RMID

猜你喜欢

转载自blog.csdn.net/weixin_40921797/article/details/82840119