linux网络编程之System V 信号量(二):用信号量实现进程互斥示

一、我们在前面讲进程间通信的时候提到过进程互斥的概念,下面写个程序来模拟一下,程序流程如下图:

即父进程打印字符O,子进程打印字符X,每次打印一个字符后要sleep 一下,这里要演示的效果是,在打印程序的边界有PV操作,故每个进程中间sleep 的时间即使时间片轮转到另一进程,由于资源不可用也不会穿插输出其他字符,也就是说O或者X字符都会是成对出现的,如OOXXOOOOXXXXXXOO….

程序如下:

C++ Code

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273#include<sys/types.h>#include<unistd.h>#include<errno.h>#include<sys/ipc.h>#include<sys/sem.h>#include<sys/wait.h>#defineERR_EXIT(m)\do{\perror(m);\exit(EXIT_FAILURE);\}while(0)unionsemun{intval;/*ValueforSETVAL*/structsemid_ds*buf;/*BufferforIPC_STAT,IPC_SET*/unsignedshort*array;/*ArrayforGETALL,SETALL*/structseminfo*__buf;/*BufferforIPC_INFO(Linux-specific)*/};intsemid;/*pv操作之间的临界区,导致打印的字符一定是成对出现的*/voidprint(charop_char){intpause_time;srand(getpid());inti;for(i=0;i<10;i++){sem_p(semid);printf("%c",op_char);fflush(stdout);pause_time=rand()%3;sleep(pause_time);printf("%c",op_char);fflush(stdout);sem_v(semid);pause_time=rand()%2;sleep(pause_time);}}intmain(void){semid=sem_create(IPC_PRIVATE);sem_setval(semid,1);pid_tpid;pid=fork();if(pid==-1)ERR_EXIT("fork");if(pid>0){print(‘o’);wait(NULL);sem_d(semid);}else{print(‘x’);}return0;}

sem_create 等函数参考工具集。在调用semget 时指定key = IPC_PRIVATE,表示创建的是私有的信号量集,但具有亲缘关系的进程是可见的,比如父子进程。输出如下:

simba@ubuntu:~/Documents/code/linux_programming/UNP/system_v$ ./printooxxooxxooxxooxxooooooxxooxxooxxooxxxxxx

可以看到输出都是成对出现的字符。

分析一下:semval = 1,假设父进程先被调度执行,父进程先P了一下,此时 semval = 0,子进程在父进程睡眠时间被调度的时候尝试P,semval = -1,然后子进程阻塞了,父进程打印完V了一下,semval = 0,唤醒子进程,子进程的P操作返回,打印字符睡眠后V了一下,semval = 1。当然在子进程睡眠的时候父进程可能也在尝试P,故就一直循环往复下去。

二、哲学家就餐问题的描述可以参考这里,下面我们尝试解决这个问题的方法是:仅当一个哲学家两边筷子都可用时才允许他拿筷子。

上图中红色数字表示哲学家的编号,总共5个哲学家,用5个进程来表示;黑色数字表示筷子的编号,总共有5根筷子,可以定义一个信号量集中含有5个信号量,每个信号量的初始值为1,当某个哲学家可以同时得到两根筷子(同时P两个信号量返回)时可以用餐,否则阻塞等待中。用餐后需要同时V一下两个信号量,让其他进程可以P成功。

程序如下:

C++ Code

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107#include<stdio.h>#include<stdlib.h>#include<sys/ipc.h>#include<sys/msg.h>#include<sys/types.h>#include<unistd.h>#include<errno.h>#include<sys/ipc.h>#include<sys/sem.h>#include<sys/wait.h>#defineERR_EXIT(m)\do{\perror(m);\exit(EXIT_FAILURE);\}while(0)unionsemun{intval;/*ValueforSETVAL*/structsemid_ds*buf;/*BufferforIPC_STAT,IPC_SET*/unsignedshort*array;/*ArrayforGETALL,SETALL*/structseminfo*__buf;/*BufferforIPC_INFO(Linux-specific)*/};intsemid;#defineDELAY(rand()%5+1)voidwait_for_2fork(intno){intleft=no;intright=(no+1)%5;structsembufbuf[2]={{left,-1,0},{right,-1,0}};semop(semid,buf,2);}voidfree_2fork(intno){intleft=no;intright=(no+1)%5;structsembufbuf[2]={{left,1,0},{right,1,0}};semop(semid,buf,2);}voidphilosopere(intno){srand(getpid());for(;;){printf("%disthinking\n",no);sleep(DELAY);printf("%dishungry\n",no);wait_for_2fork(no);printf("%diseating\n",no);sleep(DELAY);free_2fork(no);}}intmain(void){semid=semget(IPC_PRIVATE,5,IPC_CREAT|0666);if(semid==-1)ERR_EXIT("semget");unionsemunsu;su.val=1;inti;for(i=0;i<5;i++){semctl(semid,i,SETVAL,su);}intno=0;pid_tpid;for(i=1;i<5;i++){pid=fork();if(pid==-1)ERR_EXIT("fork");if(pid==0){no=i;break;}}philosopere(no);return0;}

我们在前面说过,当需要对一个信号量集中的多个信号量操作时,要么全部执行,要么全部不执行,即是一个原子操作,某个进程需要等待两根筷子,即对两个信号量同时P成功才可以用餐,信号量的序号是0~4,可看作筷子的编号,此时semop 函数操作的是2个信号量,即需定义2个struct sembuf 结构体成员的数组 struct sembuf buf[2];

simba@ubuntu:~/Documents/code/linux_programming/UNP/system_v$ ./dinning0 is thinking3 is thinking2 is thinking4 is thinking1 is thinking4 is hungry4 is eating0 is hungry3 is hungry1 is hungry1 is eating2 is hungry3 is eating4 is thinking1 is thinking0 is eating4 is hungry0 is thinking1 is hungry1 is eating3 is thinking4 is eating0 is hungry1 is thinking2 is eating0 is eating4 is thinking2 is thinking1 is hungry3 is hungry3 is eating

0 is thinking2 is hungry1 is eating4 is hungry

…………….

如果发现程序没有运行卡着,即没有发生死锁现象,从中也可以发现同时最多只能有两个哲学家一起用餐,也不会出现相邻哲学家一起用餐的情况。

参考:

《UNP》我不敢说我可以忘却,或者勇敢,坚强,等等等等一切堂皇而陈旧的字眼。

linux网络编程之System V 信号量(二):用信号量实现进程互斥示

相关文章:

你感兴趣的文章:

标签云: