在操作系统中,使用信号量可以解决进程间的,信号量是进程通信方式
进程间通信——信号量信号量类似于道路上的红绿灯,在各个路口控制人们各个方向的前进,以便更好地有计划地使用这条道路。在程序中,信号控制进程的执行。什么是信号量问题:在一个程序中,有时有一段特殊的代码,同一时间只允许一个进程执行这部分代码。这个区域被称为“关键区域”。那么,在多进程并发执行中,当一个进程进入临界区时,由于某种原因被挂起,其他进程也可能进入该区。解决方法:3354使用信号量。什么是信号量?信号量是一个特殊的变量。我们只能对信号量执行P和V操作。p:申请资源。如果信号量值为0,则信号量为-1。如果信号量值=0,则进程被挂起。操作:释放资源。如果一个进程由于信号量而被挂起,当前进程将被恢复。如果没有进程因信号量而挂起,则将信号量设置为1。注意:P操作和V操作是原子操作,即在执行过程中不会被中断。这里的信号量是指System V IPC的信号量,与线程使用的信号量不同。这个信号量用于进程间通信。使用信号量的Semget函数原型:intsemget (key _ tkey,intnsems,intsemflg);函数:获取一个现有的信号量或创建一个新的信号量,并返回信号量的标识符。参数:key:键值,对应一个唯一的信号量。键值类似于共享内存。不同的可以通过这个键值和semget获得唯一的信号量。特殊键值——IPC_PRIVAT,只能由创建者进程访问,可用于父进程与子进程之间的通信。Nsems:所需信号量的数量,通常为1。Semflag:访问权限。如果设置了IPC_CREAT,如果信号量不存在,将创建信号量,如果信号量已经存在,则不会出现错误。返回值:成功:返回正整数。失败:返回-1。信号量运算的Semop函数原型:intsemop (intsemid,structsembuf * sops,unsigned ns ops);功能:改变信号量的值,即对信号量进行P运算和V运算。参数:semid:信号量标识符,即semget函数的返回值。Sops:是一个数组,元素类型是struct sembuf。struct sembuf { short sem _ num//信号量组中的编号(即指定操作哪个信号量)//semget实际上是获取一组信号量//信号量组中的编号从0开始短sem _ op//操作类型:-1表示P操作;1 v操作短路sem _ flg//通常是SEM_UNDO,让操作系统跟踪信号,//并在进程终止时释放信号量而不释放信号量}
Nsops:表示第二个参数sops表示的数组大小,也就是有几个struct sembuf。返回值:成功:返回0。失败:返回-1。参考与补充:Linux进程间通信(5): semget()、semop()、semctl()信号量控制semctl函数原型:intsemctl (intsemid,intsem _ num,intcmd,);功能:控制信号量。参数:semid:信号量标识符。Sem_num:信号量组中的编号。如果只有一个信号量,取0。Cmd:通常是以下两个值之一。SETVAL:用于将信号量初始化为一个已知值。p的值由union semun中的val成员设置,该成员用于在第一次使用信号量之前设置信号量。IPC_RMID:用于删除不再需要的信号量标识符。这四个参数类型是:union semun。工会联合会
int val//要由setval命令设置的值
struct semid _ ds * buf
无符号短*数组;
}
Union semun有些Linux发行版是在sys/sem.h中定义的,有些则是未定义的。可以自己定义:#if defined(__GNU_LIBRARY__)!defined(_ SEM _ SEMUN _ UNDEFINED)# else
工会联合会
int val
struct semid _ ds * buf
无符号短整型*数组;
struct seminfo * _ _ buf
#endif
返回值:省略,详见-semctl (2)-Linux手册页。相关参考及补充:Linux进程间通信(5):信号量semget()、semop()、semctl()示例例1:不使用信号量同时执行多个程序,观察对临界段的访问。#包含stdlib.h
#包含stdio.h
int main(void) {
int I;
PID _ t PD=fork();
for(I=0;i i ) {
/*模拟关键区域-开始*/
printf(Process(%d) In\n ,getpid());
睡眠(1);
printf(Process(%d) Out\n ,getpid());
/*模拟临界区-结束*/
睡眠(1);
}
返回0;
}
可见不是我们想要的效果。我们要的是一个能进,一个不能进,一个能出,一个能进。
例2:使用信号量,并发指定多个进程,观察对临界区的访问。#包含sys/types.h
#包含sys/ipc.h
#包含系统/sem.h
#包含stdlib.h
#包含stdio.h
#如果定义了(__GNU_LIBRARY__)!已定义(_SEM_SEMUN_UNDEFINED)
#否则
工会联合会
int val
struct semid _ ds * buf
无符号短整型*数组;
struct seminfo * _ _ buf
};
#endif
//信号的初始化
静态SEM _ initial(int semi){
int ret
联盟semun semun
semun . val=1;
ret=SEM CTL(semi,0,SETVAL,semun);
if(ret==-1){
fprintf(stderr, semctl失败!\ n’);
}
返回ret
}
//将p v操作封装到一个函数中
//p操作
静态int SEM _ p(int semi){
int ret
结构sembuf sembuf
sembuf . SEM _ op=-1;//运算类型,设置为-1,即P运算。
SEM buf . SEM _ num=0;//指定信号量组中信号量的数量。
SEM buf . SEM _ flg=SEM _ UNDO;//让操作系统跟踪信号,如果进程忘记释放,操作系统会负责释放。
ret=semop(semi,sembuf,1);//根据设置操作信号量
if (ret==-1) {
fprintf(stderr, sem_p失败!\ n’);
}
返回ret
}
//v操作
静态int SEM _ v(int semi){
int ret
结构sembuf sembuf
SEM buf . SEM _ op=1;//运算类型,设置为1,即V运算。
SEM buf . SEM _ num=0;//指定信号量组中信号量的数量。
SEM buf . SEM _ flg=SEM _ UNDO;//让操作系统跟踪信号,如果进程忘记释放,操作系统会负责释放。
ret=semop(semi,sembuf,1);//根据设置操作信号量
if (ret==-1) {
fprintf(stderr, sem_v失败!\ n’);
}
返回ret
}
int main(int argc,char* argv[]) {
int semid
//获得信号
semi=SEM get((key _ t)1234,1,0666 IPC _ CREAT);
if(semi==-1){
printf(semget失败!\ n’);
出口(1);
}
//信号量的初始化
if (argc 1) {
int ret=SEM _ initial(semi);
if (ret==-1) {
出口(1);
}
}
for(;){
if(SEM _ p(semi)==-1){//p operation,application,如果没有可用的资源,则暂停等待。
出口(1);
}
/*模拟关键区域-开始*/
printf(Process(%d) In\n ,getpid());
睡眠(3);
printf(Process(%d) Out\n ,getpid());
/*模拟临界区-结束*/
if(SEM _ v(semi)==-1){//v运算,释放。
出口(1);
}
}
返回0;
}
你看,一个能出来,一个能进去。
转载请联系作者取得转载授权,否则将追究法律责任。
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。