1、实验二进程同步实验实验二 进程同步一、实验目的:掌握根本的同步算法,理解经典进程同步问题的本质;学习使用Linux的进程同步机制,掌握相关API的使用方法;能利用信号量机制,采用多种同步算法实现不会发生死锁的哲学家进餐程序。二、实验平台:虚拟机:VMWare9以上操作系统:Ubuntu12.04以上编辑器:Gedit | Vim编译器:Gcc三、实验容:1以哲学家进餐模型为依据,在Linux控制台环境下创立5个进程,用semget函数创立一个信号量集5个信号量,初值为1,模拟哲学家的思考和进餐行为:每一位哲学家饥饿时,先拿起左手筷子,再拿起右手筷子;筷子是临界资源,为每一支筷子定义1个互斥信号
2、量;想拿到筷子需要先对信号量做P操作,使用完释放筷子对信号量做V操作。伪代码描述:semaphore chopstick5=1,1,1,1,1;第i位哲学家的活动可描述为: doprintf(%d is thinkingn,i);printf(%d is hungryn,i); wait(chopsticki); /拿左筷子 wait(chopstick(i+1) % 5); /拿右筷子 printf(%d is eatingn,i); signal(chopsticki); /放左筷子 signal(chopstick(i+1) % 5); /放右筷子 whiletrue; 运行该组进程,观
3、察进程是否能一直运行下去,假设停滞那么发生了什么现象?并分析原因。2解决哲学家进餐问题可采用如下方法:a.仅当哲学家的左、右两只筷子均可用时,才允许他拿起筷子进餐;b.至多只允许有4位哲学家同时去拿左边的筷子,最终能保证至少有一位哲学家能够进餐;c.规定奇数号哲学家先拿起他左手的筷子,然后再拿起他右手的筷子,而偶数号哲学家那么先拿起他右手的筷子,然后再拿起他左手的筷子。方法a在例如程序中给出,请用方法b和c写出不会发生死锁的哲学家进餐程序。 3设计程序,实现生产者/消费者进程(线程)的同步与互斥。在该程序中创立4个进程或线程模拟生产者和消费者,实现进程(线程)的同步与互斥。实验结果:使用a方法
4、结果哲学家就餐问题使用b方法解决哲学家就餐问题源码如下:#include #include #include #include #include #include #include #include #include #include #include #include union semunint val;struct semid_ds *buf;unsigned short *array;struct seminfo *_buf;#define ERR_EXIT(m) do perror(m); exit(EXIT_FAILURE); while(0)/获取互斥信号量void wait_m
5、utex(int mutex)struct sembuf sb=0,-1,0;semop(mutex,&sb,1);/对互斥信号量进展操作/取得筷子void wait_v(int semid,int num)struct sembuf sb=num,-1,0;semop(semid,&sb,1);/释放筷子void signal_p(int semid,int num)struct sembuf sb=num,1,0;semop(semid,&sb,1);/释放互斥变量mutexvoid signal_mutex(int semid0)struct sembuf sb=0,1,0;semop(
6、semid0,&sb,1);/ph函数void ph(int num,int semid,int semid0)int left=num;int right=(num+1)%5;for(;)printf(%d is thinkingn,num);sleep(1);printf(%d is hungryn,num);sleep(1);/wait操作,控制哲学家最多4人能进餐wait_mutex(semid0);wait_v(semid,left);wait_v(semid,right);printf(%d is eatingn,num);sleep(1);/signal操作signal_p(se
7、mid,right);/释放右筷子signal_p(semid,left);/释放左快子signal_mutex(semid0);/释放互斥信号量/主函数int main(int argc,char *argv)int semid,semid0;/创立两个信号量集semid0=semget(IPC_PRIVATE,1,IPC_CREAT | 0666);semid=semget(IPC_PRIVATE,5,IPC_CREAT | 0666);/union semun su;su.val=1;int i;for(i=0;i5;i+)/semctl()系统调用在一个信号量集(或集合中的单个信号量)
8、上执行各种控制操作semctl(semid,i,SETVAL,su);/设定semid0信号量的初始值union semun su0;su0.val=4;semctl(semid0,0,SETVAL,su0);/创立4个子进程int num=0;pid_t pid;for(i=1;i5;i+)pid=fork();if(pid0) ERR_EXIT(fork);if(pid=0) num=i;break;/第num个哲学家要做的事ph(num,semid,semid0);return 0;执行结果使用c方法解决哲学家就餐问题#include #include #include #include
9、 #include #include #include #include #include #include #include #include union semunint val;struct semid_ds *buf;unsigned short *array;struct seminfo *_buf;#define ERR_EXIT(m) do perror(m); exit(EXIT_FAILURE); while(0)/取得筷子void wait_v(int semid,int num)struct sembuf sb=num,-1,0;semop(num,&sb,1);/释放筷
10、子void signal_p(int semid,int num)struct sembuf sb=num,-1,0;semop(num,&sb,1);/科学家要做的事void ph(int semid,int num)for(;)/死循环/判断哲学家的编号是奇数还是偶数/奇数先申请左边的筷子,偶数先申请右边的筷子if(num%2!=0)/判断奇数printf(%d is thinkingn,num);sleep(1);printf(%d is hungryn,num);sleep(1);/wait操作wait_v(semid,num);wait_v(semid,(num+1)%5);prin
11、tf(%d is eatingn,num);sleep(1);/signal操作signal_p(semid,(num+1)%5);signal_p(semid,num);if(num%2=0)/判断偶数printf(%d is thinkingn,num);sleep(1);printf(%d is hungryn,num);sleep(1);/wait操作wait_v(semid,(num+1)%5);wait_v(semid,num);/signal操作signal_p(semid,num);signal_p(semid,(num+1)%5);int main(int argc,char
12、 *argv)int semid;/创立5个信号量semid=semget(IPC_PRIVATE,5,IPC_CREAT | 0666);union semun su;su.val=1;int i;for(i=0;i5;i+)/注意第二个参数也是索引semctl(semid,i,SETVAL,su);/创立4个子进程pid_t pid;int num=5;for(i=0;i4;i+)pid=fork();if(pid0) ERR_EXIT(fork);if(pid=0) num=i;break;/哲学家要做的事ph(semid,num);return 0;生产者和消费者的同步与互斥源代码如下
13、:#include #include #include #include #include #define N 2 / 消费者或者生产者的数目#define M 10 / 缓冲数目int in = 0; / 生产者放置产品的位置int out = 0; / 消费者取产品的位置int buffM = 0; / 缓冲初始化为0, 开场时没有产品sem_t empty_sem; / 同步信号量, 当满了时阻止生产者放产品sem_t full_sem; / 同步信号量, 当没产品时阻止消费者消费pthread_mutex_t mutex; / 互斥信号量, 一次只有一个线程访问缓冲int produc
14、t_id = 0; /生产者idint prochase_id = 0; /消费者id/* 打印缓冲情况 */void print() int i; for(i = 0; i M; i+) printf(%d , buffi); printf(n);/* 生产者方法 */ void *product() int id = +product_id; while(1) / 用sleep的数量可以调节生产和消费的速度,便于观察 sleep(1); /sleep(1); sem_wait(&empty_sem); pthread_mutex_lock(&mutex); in = in % M; pri
15、ntf(product%d in %d. like: t, id, in); buffin = 1; print(); +in; pthread_mutex_unlock(&mutex); sem_post(&full_sem); /* 消费者方法 */void *prochase() int id = +prochase_id; while(1) / 用sleep的数量可以调节生产和消费的速度,便于观察 sleep(1); /sleep(1); sem_wait(&full_sem); pthread_mutex_lock(&mutex); out = out % M; printf(pro
16、chase%d in %d. like: t, id, out); buffout = 0; print(); +out; pthread_mutex_unlock(&mutex); sem_post(&empty_sem); int main() pthread_t id1N; pthread_t id2N; int i; int retN; / 初始化同步信号量 int ini1 = sem_init(&empty_sem, 0, M); int ini2 = sem_init(&full_sem, 0, 0); if(ini1 & ini2 != 0) printf(sem init f
17、ailed n); exit(1); /初始化互斥信号量 int ini3 = pthread_mutex_init(&mutex, NULL); if(ini3 != 0) printf(mutex init failed n); exit(1); / 创立N个生产者线程 for(i = 0; i N; i+) reti = pthread_create(&id1i, NULL, product, (void *)(&i); if(reti != 0) printf(product%d creation failed n, i); exit(1); /创立N个消费者线程 for(i = 0;
18、 i N; i+) reti = pthread_create(&id2i, NULL, prochase, NULL); if(reti != 0) printf(prochase%d creation failed n, i); exit(1); /销毁线程 for(i = 0; i N; i+) pthread_join(id1i,NULL); pthread_join(id2i,NULL); exit(0); 执行结果:实验总结哲学家进餐的问题是操作系统信号量同步的经典例题了。这次我通过解决哲学家进餐的哲学问题从而对进程同步有一个更好的理解,解决这个问题书中给出了三种解决方法。我在实验中也是用这三种方法去定义信号量解决死锁问题。通过信号量的获取与wait操作去控制进餐,a方法是控制哲学家左右手都有筷子时才能进餐,b中那么是通过互斥信号量的获取,假设没有信号量便不能执行,而且只有四个哲学家能同时进餐也防止了死锁的出现。c中是让奇数的哲学家先拿左筷子执行wait和signal操作,偶数号的虽然也执行该操作但是只能拿右筷子。
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1