[操作系统] pthread同步互斥:十字路口小车的死锁
来源:互联网 发布:进击的巨人剧透 知乎 编辑:程序博客网 时间:2024/05/16 11:40
不知道做的对不对,仅供参考。
更新日志:
解决了程序不能自动退出的bug(卡在死锁检测线程的while)
去掉main中最后一行:pthread_join(check,NULL) 主线程不等待死锁线程结束,程序可以自动退出。
1. 有两条道路双向两个车道,即每条路每个方向只有一个车道,两条道路十字交叉。假设车辆只能向前直行,而不允许转弯和后退。如果有4辆车几乎同时到达这个十字路口,如图(a)所示;相互交叉地停下来,如图(b),此时4辆车都将不能继续向前,这是一个典型的死锁问题。从操作系统原理的资源分配观点,如果4辆车都想驶过十字路口,那么对资源的要求如下:
l 向北行驶的车1需要象限a和b;
l 向西行驶的车2需要象限b和c;
l 向南行驶的车3需要象限c和d;
l 向东行驶的车4需要象限d和a。
我们要实现十字路口交通的车辆同步问题,防止汽车在经过十字路口时产生死锁和饥饿。在我们的系统中,东西南北各个方向不断地有车辆经过十字路口(注意:不只有4辆),同一个方向的车辆依次排队通过十字路口。按照交通规则是右边车辆优先通行,如图(a)中,若只有car1、car2、car3,那么车辆通过十字路口的顺序是car3->car2->car1。车辆通行总的规则:
1) 来自同一个方向多个车辆到达十字路口时,车辆靠右行驶,依次顺序通过;
2) 有多个方向的车辆同时到达十字路口时,按照右边车辆优先通行规则,除非该车在十字路口等待时收到一个立即通行的信号;
3) 避免产生死锁;
4) 避免产生饥饿;
5) 任何一个线程(车辆)不得采用单点调度策略;
6) 由于使用AND型信号量机制会使线程(车辆)并发度降低且引起不公平(部分线程饥饿),本题不得使用AND型信号量机制,即在上图中车辆不能要求同时满足两个象限才能顺利通过,如南方车辆不能同时判断a和b是否有空。
编写程序实现避免产生死锁和饥饿的车辆通过十字路口方案,并给出详细的设计方案,程序中要有详细的注释。
1) 每一辆车的行为设计为一个单独的线程。由于有4个不同方向的车辆,需要4种不同类型的线程。
2) 使用pthread的互斥锁和条件变量解决车辆的同步与互斥。
3) 对4个不同方向的车辆,要设置车辆队列条件变量如: queueNorth、queueEast、queueSouth、queueWest。比如说,当一辆车从北方来的时候已经在过十字路口,另一辆从北方驶来的车就要等在queueNorth队列中。每一个方向都需要一个计数器来跟踪等待排队的车辆数量。
4) 按照右边车辆优先通行规则,当一辆车在等待通过路口而它右边不断有车辆到达时,这辆车及这个方向车辆队列会导致饥饿。为了防止饥饿,我们要让刚刚通过路口的A车辆发一个信号给它左边等待的B车辆,接下去让B车辆通行。需要设置下次通行车辆的条件变量firstNorth, firstEast, firstSouth,firstWest
5) 每一车辆到达十字路口时,要检测是否有死锁发生,当发生死锁时,死锁检测线程必须发出一种信号,例如:从北方来的车辆先行。
6) 假设我们设计的可执行程序文件名为p1-1,可以用'e'、'w'、's'、'n'来标识东西南北4个方向驶来的车辆,程序p1-1运行时有如下显示(你的程序不一定是这样相同的输出):
$ ./ p1-1 nsewwewn
car 4 from West arrives at crossing
car 2 from South arrives at crossing
car 1 from North arrives at crossing
car 3 from East arrives at crossing
DEADLOCK: car jam detected, signalling North to go
car 1 from North leaving crossing
car 3 from East leaving crossing
car 2 from South leaving crossing
car 4 from West leaving crossing
car 6 from East arrives at crossing
car 5 from West arrives at crossing
car 8 from North arrives at crossing
car 5 from West leaving crossing
car 6 from East leaving crossing
car 8 from North leaving crossing
car 7 from West arrives at crossing
car 7 from West leaving crossing
对于题目中要求的车辆优先权的理解:
两车都希望占据路口a,由于西边的车(W1车)在北边车(N车)的右边,它具有优先权,将先行。
W1车离开后,虽然对于N车来说,右边还有车,但是离开的车有必要告诉N车让其优先通行。
实际上是这样处理的:设计了一个布尔量,每个方向各有一个,当车辆处在就绪状态(如左图的W1车),或者进入第一个路口时,标记布尔量为真,离开第一个路口时,标记布尔量为假。当车辆想要进入第二个路口时,需要检查它右边车的布尔量。如果为真,那么该车停等。
该布尔量在小车进入就绪队列时就设为真,如果它当时还不为真,就认为这辆车还没有进入就绪状态,也就不是同时到达路口,所以不会出现不同步现象。
N车过路口d(发现右边有车,等待)
W1车过路口a
W1车过路口b(唤醒N车)
N车过路口a(接到信号,过第二个路口,发送一个信号唤醒W2车)
W2车过路口a(接到信号,过路口a)
新的车谁来唤醒:
新的车有两种唤醒方式:
1.如果当前方向的车离开后,左边没有车等待,那么它自己唤醒当前方向的一辆车。
2.如果当前方向的车离开后,左边有车等待,那么它唤醒左边的车,并由左边的车来唤醒其方向的一辆车。
由于左边要么有车等待,要么没有车等待,所以总会有一个结果被执行,因此我们保证了一定会有新的车被唤醒。
#include <pthread.h> #include <stdio.h> #include <unistd.h>#include <stdlib.h>#include <string.h>#define MAX 100//mutex of the 4 crosspthread_mutex_t mutex_a;pthread_mutex_t mutex_b;pthread_mutex_t mutex_c;pthread_mutex_t mutex_d;//mutex of deadlock threadpthread_mutex_t mutex_e;//mutex of car waiting(in ready queue)pthread_mutex_t wait_east;pthread_mutex_t wait_west;pthread_mutex_t wait_north;pthread_mutex_t wait_south;//mutex of car waiting(in the first cross)pthread_mutex_t block_east;pthread_mutex_t block_west;pthread_mutex_t block_north;pthread_mutex_t block_south;//cond of each direction(in the first cross)pthread_cond_t cond_w;pthread_cond_t cond_e;pthread_cond_t cond_n;pthread_cond_t cond_s;//cond of each direction(in the ready queue)pthread_cond_t firstEast;pthread_cond_t firstWest;pthread_cond_t firstSouth;pthread_cond_t firstNorth;//cond when deadlock happen(to wake up the deadlock thread)pthread_cond_t cond_deadlock;//cond when deadlock happen(to wake up the car on the right)pthread_cond_t cond_lock;typedef enum { west, north, south, east }dir_t;dir_t dir;//indicate the direction of the new car that comes to the crossint size = 0;//count the number of carint empty;//record the number of empty cross//indicate the current id of car in each directionint current_north;int current_south;int current_east;int current_west;//save all the threadpthread_t car[MAX];//a data structure:queue, that descirbes the car in each directionstruct queue{pthread_t thread[MAX];int num[MAX];//the id of the carint front;//front pointerint rear;//rear pointerint count;//the number of car in the queuequeue() {front = rear = count = 0;}void push(int n) {//push a car at the back with id ncount++;rear = (rear + 1) % MAX;num[rear] = n;}int pop() {//pop a car in the front,return the car idcount--;front = (front + 1) % MAX;return num[front];}};//the queue of carqueue car_south;queue car_east;queue car_north;queue car_west;//if each direction has a car leaving the ready queue /or coming to the first crossbool is_west;bool is_south;bool is_east;bool is_north;//if deadlock happensbool is_deadlock = false;//wake up all car in the front of the ready queuevoid wakeupall(){is_deadlock = false;if (car_south.count>0) {current_south = car_south.pop();//I think this variable has better be designed as a member variable of the class queue//but I am too lazy.pthread_cond_signal(&firstSouth);}if (car_north.count>0) {current_north = car_north.pop();pthread_cond_signal(&firstNorth);}if (car_west.count>0) {current_west = car_west.pop();pthread_cond_signal(&firstWest);}if (car_east.count>0) {current_east = car_east.pop();pthread_cond_signal(&firstEast);}}void *car_from_south(void *arg) {bool deadlock_flag = false;//add a wait lockpthread_mutex_lock(&wait_south);pthread_cond_wait(&firstSouth, &wait_south);pthread_mutex_unlock(&wait_south);//has come to the crossis_south = true;//set is_come to be true//add a lock to the crosspthread_mutex_lock(&mutex_a);printf("car %d from South arrives at crossing\n", current_south);//the resource minus 1empty--;//indicate current directiondir = south;bool flag = false;//if the resource is used upif (empty == 0) {//deadlock happened, send a signal to deadlock threadpthread_cond_signal(&cond_deadlock);//wait until the deadlock is solvedpthread_cond_wait(&cond_lock, &mutex_a);usleep(2000);pthread_mutex_lock(&mutex_b);pthread_mutex_unlock(&mutex_a);printf("car %d from South leaves at crossing\n", current_south);is_south = false;//resource add 1.empty++;usleep(2000);pthread_mutex_unlock(&mutex_b);wakeupall();return NULL;}//if it find a car on its rightelse if (is_east) {// printf("a car on south's right\n");flag = true;//it will wait for the car to go firstpthread_cond_wait(&cond_s, &block_south);//the car is gone, remember to call the new car//and it is wake up, and find that deadlock happend//it has to wake up the left carif (is_deadlock) {usleep(2000);pthread_mutex_lock(&mutex_b);pthread_mutex_unlock(&mutex_a);printf("car %d from South leaves at crossing\n", current_south);if (dir == west)pthread_cond_signal(&cond_lock);else pthread_cond_signal(&cond_w);is_south = false;//resource add 1.empty++;usleep(2000);pthread_mutex_unlock(&mutex_b);return NULL;}}usleep(2000);//come to the second crosspthread_mutex_lock(&mutex_b);//if flag, remember to callif (car_east.count>0 && flag) {current_east = car_east.pop();pthread_cond_signal(&firstEast);}//release the lockpthread_mutex_unlock(&mutex_a);is_south = false;//resource add 1.empty++;printf("car %d from South leaves at crossing\n", current_south);//if a car is waiting on the left, let it go//and the waiting car in the queue is waked up by itif (is_west)pthread_cond_signal(&cond_w);//or it's waked up by itselfelse if (!is_south && car_south.count>0) {current_south = car_south.pop();pthread_cond_signal(&firstSouth);}usleep(2000);//unlockpthread_mutex_unlock(&mutex_b);}void *car_from_east(void *arg) {//add a wait lockpthread_mutex_lock(&wait_east);pthread_cond_wait(&firstEast, &wait_east);pthread_mutex_unlock(&wait_east);//has come to the crossis_east = true;//setis_come to be true //add a lock to crosspthread_mutex_lock(&mutex_b);printf("car %d from East arrives at crossing\n", current_east);empty--;dir = east;bool flag = false;if (empty == 0) {pthread_cond_signal(&cond_deadlock);pthread_cond_wait(&cond_lock, &mutex_b);usleep(2000);pthread_mutex_lock(&mutex_c);pthread_mutex_unlock(&mutex_b);printf("car %d from East leaves at crossing\n", current_east);is_east = false;//resource add 1.empty++;usleep(2000);pthread_mutex_unlock(&mutex_c);wakeupall();return NULL;}// if it find a car on its rightelse if (is_north) {flag = true;//it will wait for the car to go firstpthread_cond_wait(&cond_e, &block_east);//it will wait for the car to go first//the car is gone, remember to call the new car//and it is wake up, and find that deadlock happend//it has to wake up the left carif (is_deadlock) {usleep(2000);pthread_mutex_lock(&mutex_c);pthread_mutex_unlock(&mutex_b);printf("car %d from East leaves at crossing\n", current_east);//if it find a car on its left is the deadlock car,wake up itif (dir == south)pthread_cond_signal(&cond_lock);//otherwise wake up the one on the leftelse pthread_cond_signal(&cond_s);is_east = false;//resource add 1.empty++;usleep(2000);pthread_mutex_unlock(&mutex_c);return NULL;}}usleep(2000);//come to the second crosspthread_mutex_lock(&mutex_c);//if flag, remember to callif (!is_north && car_north.count>0 && flag) {current_north = car_north.pop();pthread_cond_signal(&firstNorth);}//release the lockempty++;pthread_mutex_unlock(&mutex_b);is_south = false;printf("car %d from East leaves at crossing\n", current_east);if (is_east)pthread_cond_signal(&cond_s);else if (!is_east && car_east.count>0) {current_east = car_east.pop();pthread_cond_signal(&firstEast);}usleep(2000);pthread_mutex_unlock(&mutex_c);}void *car_from_north(void *arg) {// printf("create north\n");//add a wait lockpthread_mutex_lock(&wait_north);pthread_cond_wait(&firstNorth, &wait_north);pthread_mutex_unlock(&wait_north);is_north = true;pthread_mutex_lock(&mutex_c);printf("car %d from North arrives at crossing\n", current_north);empty--;dir = north;bool flag = false;if (empty == 0) {//deadlock happened, send a signal to deadlock threadpthread_cond_signal(&cond_deadlock);//wait until the deadlock is solvedpthread_cond_wait(&cond_lock, &mutex_c);pthread_cond_signal(&cond_e);usleep(2000);pthread_mutex_lock(&mutex_d);pthread_mutex_unlock(&mutex_c);printf("car %d from West leaves at crossing\n", current_north);is_north = false;//resource add 1.empty++;usleep(2000);pthread_mutex_unlock(&mutex_d);wakeupall();return NULL;}//if it find a car on its rightelse if (is_west) {// printf("a car on north's right\n");flag = true;//it will wait for the car to go firstpthread_cond_wait(&cond_n, &block_north);//the car is gone, remember to call the new car//and it is wake up, and find that deadlock happend//it has to wake up the left carif (is_deadlock) {usleep(2000);pthread_mutex_lock(&mutex_d);pthread_mutex_unlock(&mutex_c);printf("car %d from North leaves at crossing\n", current_north);if (dir == east)pthread_cond_signal(&cond_lock);else pthread_cond_signal(&cond_e);is_north = false;//resource add 1.empty++;usleep(2000);pthread_mutex_unlock(&mutex_d);return NULL;}}usleep(2000);pthread_mutex_lock(&mutex_d);//if flag, remember to call the right carif (car_west.count>0 && flag) {current_west = car_west.pop();pthread_cond_signal(&firstWest);}empty++;pthread_mutex_unlock(&mutex_c);is_north = false;printf("car %d from North leaves at crossing\n", current_north);if (is_east)pthread_cond_signal(&cond_e);//or it's waked up by itselfelse if (!is_north && car_north.count>0) {current_north = car_north.pop();pthread_cond_signal(&firstNorth);}usleep(2000);pthread_mutex_unlock(&mutex_d);}void *car_from_west(void *arg) {//add a wait lockpthread_mutex_lock(&wait_west);pthread_cond_wait(&firstWest, &wait_west);pthread_mutex_unlock(&wait_west);//has come to the crossis_west = true;//set is_come to be truepthread_mutex_lock(&mutex_d);printf("car %d from West arrives at crossing\n", current_west);//the resource minus 1empty--;//indicate current directiondir = west;bool flag = false;//if the resource is used upif (empty == 0) {//deadlock happened, send a signal to deadlock threadpthread_cond_signal(&cond_deadlock);//wait until the deadlock is solvedpthread_cond_wait(&cond_lock, &mutex_d);usleep(2000);pthread_mutex_lock(&mutex_a);pthread_mutex_unlock(&mutex_d);printf("car %d from West leaves at crossing\n", current_west);is_south = false;//resource add 1.empty++;usleep(2000);pthread_mutex_unlock(&mutex_a);wakeupall();return NULL;}//if it find a car on its rightelse if (is_south) {flag = true;//it will wait for the car to go firstpthread_cond_wait(&cond_w, &block_west);//the car is gone, remember to call the new car//and it is wake up, and find that deadlock happend//it has to wake up the left carif (is_deadlock) {usleep(2000);pthread_mutex_lock(&mutex_a);pthread_mutex_unlock(&mutex_d);printf("car %d from West leaves at crossing\n", current_west);if (dir == north)pthread_cond_signal(&cond_lock);else pthread_cond_signal(&cond_n);is_west = false;//resource add 1.empty++;usleep(2000);pthread_mutex_unlock(&mutex_a);return NULL;}}usleep(2000);//come to the second crosspthread_mutex_lock(&mutex_a);//if flag, remember to callif (!is_north && car_north.count>0 && flag) {current_north = car_north.pop();pthread_cond_signal(&firstNorth);}empty++;pthread_mutex_unlock(&mutex_d);is_west = false;printf("car %d from West leaves at crossing\n", current_west);if (is_north)pthread_cond_signal(&cond_n);else if (!is_west && car_west.count>0) {current_west = car_west.pop();pthread_cond_signal(&firstWest);}usleep(2000);pthread_mutex_unlock(&mutex_a);}void *check_dead_lock(void *arg) {//wait....usleep(4000);//at first wake up all the car;wakeupall();while (1) {pthread_mutex_lock(&mutex_e);//wait for deadlockpthread_cond_wait(&cond_deadlock, &mutex_e);//deadlock happen,set is_deadlock trueis_deadlock = true;printf("DEADLOCK: car jam detected, signalling");//ask a car to go first,according to the latest car direction.switch (dir) {case north: {printf(" East "); pthread_cond_signal(&cond_e); break; }case east: {printf(" South "); pthread_cond_signal(&cond_s); break; }case west: {printf(" North "); pthread_cond_signal(&cond_n); break; }case south: {printf(" West "); pthread_cond_signal(&cond_w); break; }}printf("to go\n");pthread_mutex_unlock(&mutex_e);}}int main(int argc, char** argv) {int num[100];pthread_t check;//a thread for deadlock checking//initialize(it seems that it doesn't matter whether I intialize)pthread_cond_init(&cond_lock, NULL);pthread_cond_init(&cond_deadlock, NULL);pthread_cond_init(&cond_w, NULL);pthread_cond_init(&cond_s, NULL);pthread_cond_init(&cond_e, NULL);pthread_cond_init(&cond_n, NULL);pthread_cond_init(&firstEast, NULL);pthread_cond_init(&firstWest, NULL);pthread_cond_init(&firstSouth, NULL);pthread_cond_init(&firstNorth, NULL);pthread_mutex_init(&mutex_a, NULL);pthread_mutex_init(&mutex_b, NULL);pthread_mutex_init(&mutex_c, NULL);pthread_mutex_init(&mutex_d, NULL);pthread_mutex_init(&mutex_e, NULL);pthread_mutex_init(&wait_north, NULL);pthread_mutex_init(&wait_south, NULL);pthread_mutex_init(&wait_east, NULL);pthread_mutex_init(&wait_west, NULL);pthread_mutex_init(&block_north, NULL);pthread_mutex_init(&block_east, NULL);pthread_mutex_init(&block_west, NULL);pthread_mutex_init(&block_south, NULL);char s[100];scanf("%s", s);int len = strlen(s);empty = 4;//create the threadfor (int i = 0; i<len; i++)num[i] = i + 1;for (int i = 0; i<len; i++) {switch (s[i]) {case 'w': {is_west = true;car_west.push(num[i]);car[size++] = car_west.thread[car_west.front];pthread_create(&car_west.thread[car_west.front],NULL, car_from_west, NULL);break;}case 'e': {is_east = true;car_east.push(num[i]);car[size++] = car_east.thread[car_east.front];pthread_create(&car_east.thread[car_east.rear],NULL, car_from_east, NULL);break;}case 's': {is_south = true;car_south.push(num[i]);car[size++] = car_south.thread[car_south.rear];pthread_create(&car_south.thread[car_south.rear],NULL, car_from_south, NULL);break;}case 'n': {is_north = true;car_north.push(num[i]);car[size++] = car_north.thread[car_north.rear];pthread_create(&car_north.thread[car_north.rear],NULL, car_from_north, NULL);break;}}}pthread_create(&check, NULL, check_dead_lock, NULL);//join the threadfor (int i = 0; i<size; i++) {pthread_join(car[i], NULL);}}
- [操作系统] pthread同步互斥:十字路口小车的死锁
- 操作系统中的互斥,同步与死锁
- [操作系统]复习四 进程 同步互斥 死锁
- 操作系统的互斥与同步
- 操作系统--进程的互斥与同步
- 同步和互斥的一些问题(死锁,优先级逆转)
- 同步和互斥的一些问题(死锁,优先级逆转)
- 同步和互斥的一些问题(死锁,优先级逆转)
- 操作系统实验--同步互斥
- 【操作系统】互斥与同步
- 操作系统清华向勇陈渝版笔记(九) 同步协同多道程序设计和并发问题,同步互斥,死锁,临界区
- Linux操作系统多线程同步互斥Mutex的使用
- 计算机操作系统知识--关于同步互斥的思考1
- 【操作系统笔记】同步与互斥的区别和联系
- 操作系统的信号量 进程互斥 同步等概念
- 操作系统课程设计-线程和进程的同步与互斥
- 操作系统--进程间的通信,同步和互斥等
- 操作系统概论(3) --进程的同步与互斥
- adobe flash player已过期
- 程序员提高课
- C语言工资信息管理系统设计
- 获取CPU信息
- static
- [操作系统] pthread同步互斥:十字路口小车的死锁
- HTML
- Servlet进行服务器端验证
- 自组织映射和特征提取、处理
- oracle入门
- CSS 6.1 定位-定位概述
- leetcode374: Guess Number Higher or Lower
- C/C++笔记
- Hystrix 使用与分析