#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <string.h>
#define MAX 100
#define SLEEP_TIME 2000
//四个方向的宏定义,为了方便数组使用
#define N 0
#define E 1
#define S 2
#define W 3
//四个路口的通行条件和配套锁
pthread_cond_t cond[4];
pthread_mutex_t cond_mutex[4];
//四个方向上等待队列的车向前的条件和配套锁
pthread_cond_t first[4];
pthread_mutex_t first_mutex[4];
//死锁发生的条件和配套锁
pthread_cond_t cond_deadlock;
pthread_mutex_t cond_deadlock_mutex;
//四个路口的资源(其实这个变量好像并不用,first和source的作用是重复的)
pthread_mutex_t source[4];
int dir; //标志引发死锁的车的方向
int size=0; //车辆总数
int cross_car_num=0; //十字路口处的车辆数(不包括等待队列)
pthread_mutex_t cross_car_num_mutex; //cross_car_num的访问锁
int current[4]; //目前每个方向上要过路口的车的id
int is_car[4]; //标志每个方向上是否有车要过路口
int deadlock_flag=0; //标志当前是否处于死锁或者解死锁状态
pthread_t car[MAX]; //所有车辆线程
pthread_t check; //死锁检测线程
pthread_t thread_id[4][MAX]; //每个方向的线程号
int car_id[4][MAX]; //每个方向的车辆号
int front[4]={0}; //每个方向车辆队列的头指针
int rear[4]={0}; //每个方向车辆队列的尾指针
int count[4]={0}; //每个方向车辆数
//把一个车辆放入其方向上的等待队列
void push(int dir, int cid) {
count[dir]++;
rear[dir] = (rear[dir] + 1) % MAX;
car_id[dir][rear[dir]] = cid;
}
//把一个车辆移除其方向上的等待队列并返回下一车辆号
int pop(int dir) {
count[dir]--;
front[dir] = (front[dir] + 1) % MAX;
return car_id[dir][front[dir]];
}
//初始化条件和锁
void initialize(){
int i;
pthread_cond_init(&cond_deadlock, NULL);
pthread_mutex_init(&cond_deadlock_mutex, NULL);
for(i=0;i<4;i++){
pthread_cond_init(&cond[i], NULL);
pthread_mutex_init(&cond_mutex[i], NULL);
pthread_cond_init(&first[i], NULL);
pthread_mutex_init(&first_mutex[i], NULL);
pthread_mutex_init(&source[i], NULL);
}
pthread_mutex_init(&cross_car_num_mutex, NULL);
}
//让这个方向的等待队列的车向前
void call_next(int dir) {
if (count[dir]>0) {
current[dir] = pop(dir); //移除前一辆车并得到当前队首
pthread_mutex_lock(&first_mutex[dir]);
pthread_cond_signal(&first[dir]); //释放向前信号
pthread_mutex_unlock(&first_mutex[dir]);
}
}
//让所有方向的等待队列的车向前
void call_next_all() {
int i;
for(i=0;i<4;i++)
call_next(i);
}
//从北边来的车的线程
void *car_from_north(void *arg) {
usleep(SLEEP_TIME);
//printf("car from North creates\n");
//现在在等待队列中,等待向前信号
pthread_mutex_lock(&first_mutex[N]);
pthread_cond_wait(&first[N], &first_mutex[N]);
pthread_mutex_unlock(&first_mutex[N]);
//变成第一个啦
//printf("car from North first\n");
is_car[N] = 1; //设置这个路口有车的标志
//要求这个方向过路口的资源
pthread_mutex_lock(&source[N]);
pthread_mutex_lock(&cross_car_num_mutex);
cross_car_num++; //路口车辆数加一
printf("car %d from North arrives at crossing\n", current[N]);
usleep(SLEEP_TIME);
if (cross_car_num == 4) { //如果路口车辆数达到4就会死锁了
//printf("north test deadlock\n");
pthread_mutex_unlock(&cross_car_num_mutex);
//告诉死锁检测线程死锁发生了
pthread_mutex_lock(&cond_deadlock_mutex);
dir = N; //记录下这个方向,为了让死锁检测进程知道是哪个方向最后引发了死锁,来决定让哪个方向的车先走
//这个变量不用自己设一个锁,因为它只会在通知死锁的时候被修改,所以和通知死锁的锁用同一个锁就可以了
pthread_cond_signal(&cond_deadlock);
pthread_mutex_unlock(&cond_deadlock_mutex);
//等待被死锁调度进程或者其他车辆唤醒
pthread_mutex_lock(&cond_mutex[N]);
pthread_cond_wait(&cond[N], &cond_mutex[N]);
pthread_mutex_unlock(&cond_mutex[N]);
//usleep(SLEEP_TIME);
//释放该方向路口资源
pthread_mutex_unlock(&source[N]);
printf("car %d from North leaves at crossing\n", current[N]);
is_car[N] = 0; //设置这个路口无车的标志
pthread_mutex_lock(&cross_car_num_mutex);
deadlock_flag=0; //设置死锁已解决的标志
cross_car_num--; //路口车辆数减一
call_next_all(); //根据死锁检测进程的机制,引发死锁的车一定死解一轮死锁中最后一个走的,所以它要唤醒四个路口的等待队列的车向前
pthread_mutex_unlock(&cross_car_num_mutex);
//usleep(SLEEP_TIME);
return NULL;
}
else if (is_car[W]==1) { //如果右边有车
// printf("a car on south's right\n");
pthread_mutex_unlock(&cross_car_num_mutex);
//等待右边的车唤醒自己
pthread_mutex_lock(&cond_mutex[N]);
pthread_cond_wait(&cond[N], &cond_mutex[N]);
pthread_mutex_unlock(&cond_mutex[N]);
//usleep(SLEEP_TIME);
//释放该方向路口资源
pthread_mutex_unlock(&source[N]);
printf("car %d from North leaves at crossing\n", current[N]);
is_car[N] = 0; //设置这个路口无车的标志
pthread_mutex_lock(&cross_car_num_mutex);
cross_car_num--; //路口车辆数减一
pthread_mutex_unlock(&cross_car_num_mutex);
//如果左边有车,告诉左边的车可以走了
//(这一句不用加判断没关系,因为signal在wait之前执行的话不起作用)
pthread_cond_signal(&cond[E]);
//如果不是在死锁状态,让自己方向的下一辆车上来
//usleep(SLEEP_TIME);
if(!deadlock_flag){
call_next(N);
}
return NULL;
}
else{ //如果没什么事我就先走了
//usleep(SLEEP_TIME);
pthread_mutex_unlock(&cross_car_num_mutex);
//释放该方向路口资源
pthread_mutex_unlock(&source[N]);
printf("car %d from North leaves at crossing\n", current[N]);
is_car[N] = 0; //设置这个路口无车的标志
pthread_mutex_lock(&cross_car_num_mutex);
cross_car_num--; //路口车辆数减一
pthread_mutex_unlock(&cross_car_num_mutex);
//如果左边有车,告诉左边的车可以走了
//(这一句不用加判断没关系,因为signal在wait之前执行的话不起作用)
pthread_cond_signal(&cond[E]);
//如果不是在死锁状态,让自己方向的下一辆车上来
//usleep(SLEEP_TIME);
if(!deadlock_flag){
call_next(N);
}
return NULL;
}
}
//从东边来的车的线程
void *car_from_east(void *arg) {
usleep(SLEEP_TIME);
//printf("car from East creates\n");
//现在在等待队列中,等待向前信号
pthread_mutex_lock(&first_mutex[E]);
pthread_cond_wait(&first[E], &first_mutex[E]);
pthread_mutex_unlock(&first_mutex[E]);
//变成第一个啦
//printf("car from East first\n");
is_car[E] = 1;
//要求这个方向过路口的资源
pthread_mutex_lock(&source[E]);
pthread_mutex_lock(&cross_car_num_mutex);
cross_car_num++; //路口车辆数加一
printf("car %d from East arrives at crossing\n", current[E]);
usleep(SLEEP_TIME);
if (cross_car_num == 4) { //如果路口车辆数达到4就会死锁了
//printf("east test deadlock\n");
pthread_mutex_unlock(&cross_car_num_mutex);
//告诉死锁检测线程死锁发生了
pthread_mutex_lock(&cond_deadlock_mutex);
dir = E; //记录下这个方向,为了让死锁检测进程知道是哪个方向最后引发了死锁,来决定让哪个方向的车先走
//这个变量不用自己设一个锁,因为它只会在通知死锁的时候被修改,所以和通知死锁的锁用同一个锁就可以了
pthread_cond_signal(&cond_deadlock);
pthread_mutex_unlock(&cond_deadlock_mutex);
//等待被死锁调度进程或者其他车辆唤醒
pthread_mutex_lock(&cond_mutex[E]);
pthread_cond_wait(&cond[E], &cond_mutex[E]);
pthread_mutex_unlock(&cond_mutex[E]);
//usleep(SLEEP_TIME);
//释放该方向路口资源
pthread_mutex_unlock(&source[E]);
printf("car %d from East leaves at crossing\n", current[E]);
is_car[E] = 0; //设置这个路口无车的标志
pthread_mutex_lock(&cross_car_num_mutex);
deadlock_flag=0; //设置死锁已解决的标志
cross_car_num--; //路口车辆数减一
call_next_all(); //根据死锁检测进程的机制,引发死锁的车一定死解一轮死锁中最后一个走的,所以它要唤醒四个路口的等待队列的车向前
pthread_mutex_unlock(&cross_car_num_mutex);
//usleep(SLEEP_TIME);
return NULL;
}
else if (is_car[N]==1) { //如果右边有车
// printf("a car on south's right\n");
pthread_mutex_unlock(&cross_car_num_mutex);
//等待右边的车唤醒自己
pthread_mutex_lock(&cond_mutex[E]);
pthread_cond_wait(&cond[E], &cond_mutex[E]);
pthread_mutex_unlock(&cond_mutex[E]);
//usleep(SLEEP_TIME);
//释放该方向路口资源
pthread_mutex_unlock(&source[E]);
printf("car %d from East leaves at crossing\n", current[E]);
is_car[E] = 0; //设置这个路口无车的标志
pthread_mutex_lock(&cross_car_num_mutex);
cross_car_num--; //路口车辆数减一
pthread_mutex_unlock(&cross_car_num_mutex);
//如果左边有车,告诉左边的车可以走了
//(这一句不用加判断没关系,因为signal在wait之前执行的话不起作用)
pthread_cond_signal(&cond[S]);
//如果不是在死锁状态,让自己方向的下一辆车上来
//usleep(SLEEP_TIME); 这个sleep很可能是需要的
if(!deadlock_flag){
call_next(E);
}
return NULL;
}
else{ //如果没什么事我就先走了
//usleep(SLEEP_TIME);
pthread_mutex_unlock(&cross_car_num_mutex);
//释放该方向路口资源
pthread_mutex_unlock(&source[E]);
printf("car %d from East leaves at crossing\n", current[E]);
is_car[E] = 0;
pthread_mutex_lock(&cross_car_num_mutex);
cross_car_num--;
pthread_mutex_unlock(&cross_car_num_mutex);
//如果左边有车,告诉左边的车可以走了
//(这一句不用加判断没关系,因为signal在wait之前执行的话不起作用)
pthread_cond_signal(&cond[S]);
//如果不是在死锁状态,让自己方向的下一辆车上来
//usleep(SLEEP_TIME); 这个sleep很可能是需要的
if(!deadlock_flag){
call_next(E);
}
return NULL;
}
}
//从南边来的车的线程
void *car_from_south(void *arg) {
usleep(SLEEP_TIME);
//printf("car from South creates\n");
//现在在等待队列中,还不是第一个可以走的
pthread_mutex_lock(&first_mutex[S]);
pthread_cond_wait(&first[S], &first_mutex[S]);
pthread_mutex_unlock(&first_mutex[S]);
//变成第一个啦
//printf("car from South first\n");
is_car[S] = 1;
//要求这个方向过路口的资源
pthread_mutex_lock(&source[S]);
pthread_mutex_lock(&cross_car_num_mutex);
cross_car_num++; //路口车辆数加一
printf("car %d from South arrives at crossing\n", current[S]);
usleep(SLEEP_TIME);
if (cross_car_num == 4) { //如果路口车辆数达到4就会死锁了
//printf("south test deadlock\n");
pthread_mutex_unlock(&cross_car_num_mutex);
//告诉死锁检测线程死锁发生了
pthread_mutex_lock(&cond_deadlock_mutex);
dir = S; //记录下这个方向,为了让死锁检测进程知道是哪个方向最后引发了死锁,来决定让哪个方向的车先走
//这个变量不用自己设一个锁,因为它只会在通知死锁的时候被修改,所以和通知死锁的锁用同一个锁就可以了
pthread_cond_signal(&cond_deadlock);
pthread_mutex_unlock(&cond_deadlock_mutex);
//等待被死锁调度进程或者其他车辆唤醒
pthread_mutex_lock(&cond_mutex[S]);
pthread_cond_wait(&cond[S], &cond_mutex[S]);
pthread_mutex_unlock(&cond_mutex[S]);
//usleep(SLEEP_TIME);
//释放该方向路口资源
pthread_mutex_unlock(&source[S]);
printf("car %d from South leaves at crossing\n", current[S]);
is_car[S] = 0; //设置这个路口无车的标志
pthread_mutex_lock(&cross_car_num_mutex);
deadlock_flag=0; //设置死锁已解决的标志
cross_car_num--; //路口车辆数减一
call_next_all(); //如果自己是死锁解完的最后一辆车,那么唤醒四个路口的等待队列的车向前
pthread_mutex_unlock(&cross_car_num_mutex);
//usleep(SLEEP_TIME);
return NULL;
}
else if (is_car[E]==1) { //如果右边有车
pthread_mutex_unlock(&cross_car_num_mutex);
// printf("a car on south's right\n");
//等待右边的车唤醒自己
pthread_mutex_lock(&cond_mutex[S]);
pthread_cond_wait(&cond[S], &cond_mutex[S]);
pthread_mutex_unlock(&cond_mutex[S]);
//usleep(SLEEP_TIME);
//释放该方向路口资源
pthread_mutex_unlock(&source[S]);
printf("car %d from South leaves at crossing\n", current[S]);
is_car[S] = 0; //设置这个路口无车的标志
pthread_mutex_lock(&cross_car_num_mutex);
cross_car_num--; //路口车辆数减一
pthread_mutex_unlock(&cross_car_num_mutex);
//如果左边有车,告诉左边的车可以走了
//(这一句不用加判断没关系,因为signal在wait之前执行的话不起作用)
pthread_cond_signal(&cond[W]);
//如果不是在死锁状态,让自己方向的下一辆车上来
//usleep(SLEEP_TIME); 这个sleep很可能是需要的
if(!deadlock_flag){
call_next(S);
}
return NULL;
}
else{ //如果没什么事我就先走了
pthread_mutex_unlock(&cross_car_num_mutex);
//usleep(SLEEP_TIME);
//释放该方向路口资源
pthread_mutex_unlock(&source[S]);
printf("car %d from South leaves at crossing\n", current[S]);
is_car[S] = 0; //设置这个路口无车的标志
pthread_mutex_lock(&cross_car_num_mutex);
cross_car_num--; //路口车辆数减一
pthread_mutex_unlock(&cross_car_num_mutex);
//如果左边有车,告诉左边的车可以走了
//(这一句不用加判断没关系,因为signal在wait之前执行的话不起作用)
pthread_cond_signal(&cond[W]);
//如果不是在死锁状态,让自己方向的下一辆车上来
//usleep(SLEEP_TIME); 这个sleep很可能是需要的
if(!deadlock_flag){
call_next(S);
}
return NULL;
}
}
//从西边来的车的线程
void *car_from_west(void *arg) {
usleep(SLEEP_TIME);
//printf("car from West creates\n");
//现在在等待队列中,还不是第一个可以走的
pthread_mutex_lock(&first_mutex[W]);
pthread_cond_wait(&first[W], &first_mutex[W]);
pthread_mutex_unlock(&first_mutex[W]);
//变成第一个啦
//printf("car from West first\n");
is_car[W] = 1;
//要求这个方向过路口的资源
pthread_mutex_lock(&source[W]);
pthread_mutex_lock(&cross_car_num_mutex);
cross_car_num++;
printf("car %d from West arrives at crossing\n", current[W]);
usleep(SLEEP_TIME);
if (cross_car_num == 4) { //如果路口车辆数达到4就会死锁了
//printf("west test deadlock\n");
pthread_mutex_unlock(&cross_car_num_mutex);
//告诉死锁检测线程死锁发生了
pthread_mutex_lock(&cond_deadlock_mutex);
dir = W; //记录下这个方向,为了让死锁检测进程知道是哪个方向最后引发了死锁,来决定让哪个方向的车先走
//这个变量不用自己设一个锁,因为它只会在通知死锁的时候被修改,所以和通知死锁的锁用同一个锁就可以了
pthread_cond_signal(&cond_deadlock);
pthread_mutex_unlock(&cond_deadlock_mutex);
//等待被死锁调度进程或者其他车辆唤醒
pthread_mutex_lock(&cond_mutex[W]);
pthread_cond_wait(&cond[W], &cond_mutex[W]);
pthread_mutex_unlock(&cond_mutex[W]);
//usleep(SLEEP_TIME);
pthread_mutex_unlock(&source[W]);
printf("car %d from West leaves at crossing\n", current[W]);
is_car[W] = 0; //设置这个路口无车的标志
pthread_mutex_lock(&cross_car_num_mutex);
deadlock_flag=0; //设置死锁已解决的标志
cross_car_num--; //路口车辆数减一
call_next_all(); //如果自己是死锁解完的最后一辆车,那么唤醒四个路口的等待队列的车向前
pthread_mutex_unlock(&cross_car_num_mutex);
//usleep(SLEEP_TIME);
return NULL;
}
else if (is_car[S]==1) { //如果右边有车
// printf("a car on south's right\n");
pthread_mutex_unlock(&cross_car_num_mutex);
//等待右边的车唤醒自己
pthread_mutex_lock(&cond_mutex[W]);
pthread_cond_wait(&cond[W], &cond_mutex[W]);
pthread_mutex_unlock(&cond_mutex[W]);
//usleep(SLEEP_TIME);
//释放该方向路口资源
pthread_mutex_unlock(&source[W]);
printf("car %d from West leaves at crossing\n", current[W]);
is_car[W] = 0; //设置这个路口无车的标志
pthread_mutex_lock(&cross_car_num_mutex);
cross_car_num--; //路口车辆数减一
pthread_mutex_unlock(&cross_car_num_mutex);
//如果左边有车,告诉左边的车可以走了
//(这一句不用加判断没关系,因为signal在wait之前执行的话不起作用)
pthread_cond_signal(&cond[N]);
//如果不是在死锁状态,让自己方向的下一辆车上来
//usleep(SLEEP_TIME); 这个sleep很可能是需要的
if(!deadlock_flag){
call_next(W);
}
return NULL;
}
else{ //如果没什么事我就先走了
pthread_mutex_unlock(&cross_car_num_mutex);
//usleep(SLEEP_TIME);
//释放该方向路口资源
pthread_mutex_unlock(&source[W]);
printf("car %d from West leaves at crossing\n", current[W]);
is_car[W] = 0; //设置这个路口无车的标志
pthread_mutex_lock(&cross_car_num_mutex);
cross_car_num--; //路口车辆数减一
pthread_mutex_unlock(&cross_car_num_mutex);
//如果左边有车,告诉左边的车可以走了
//(这一句不用加判断没关系,因为signal在wait之前执行的话不起作用)
pthread_cond_signal(&cond[N]);
//如果不是在死锁状态,让自己方向的下一辆车上来
//usleep(SLEEP_TIME); 这个sleep很可能是需要的
if(!deadlock_flag){
call_next(W);
}
return NULL;
}
}
void *check_dead_lock(void *arg) {
usleep(SLEEP_TIME);
//printf("check_dead_lock creates\n");
usleep(2*SLEEP_TIME); //等所有线程都创建完(就是所有车都开到路口等了)
call_next_all(); //召唤四个方向等待队列的车向前
while (1) {
//等待死锁进程被触发
pthread_mutex_lock(&cond_deadlock_mutex);
pthread_cond_wait(&cond_deadlock, &cond_deadlock_mutex);
pthread_mutex_unlock(&cond_deadlock_mutex);
deadlock_flag=1; //标志死锁状态
//printf("DEADLOCK: %d ",dir); //测试用
//发一个信号让一个方向的车先走(让引发死锁的车的左边的车先走)
switch (dir) {
case N: {
//printf(" East ");
printf("DEADLOCK: car jam detected, signalling East to go\n");
pthread_mutex_lock(&cond_mutex[E]);
pthread_cond_signal(&cond[E]);
pthread_mutex_unlock(&cond_mutex[E]);
break;
} //如果引发死锁的是N,让E先走
case E: {
printf("DEADLOCK: car jam detected, signalling South to go\n");
pthread_mutex_lock(&cond_mutex[S]);
pthread_cond_signal(&cond[S]);
pthread_mutex_unlock(&cond_mutex[S]);
break;
} //如果引发死锁的是N,让E先走
case W: {
printf("DEADLOCK: car jam detected, signalling North to go\n");
pthread_mutex_lock(&cond_mutex[N]);
pthread_cond_signal(&cond[N]);
pthread_mutex_unlock(&cond_mutex[N]);
break;
} //如果引发死锁的是N,让E先走
case S: {
printf("DEADLOCK: car jam detected, signalling West to go\n");
pthread_mutex_lock(&cond_mutex[W]);
pthread_cond_signal(&cond[W]);
pthread_mutex_unlock(&cond_mutex[W]);
break;
} //如果引发死锁的是N,让E先走
}
}
}
void thread_wait(){
int i;
usleep(SLEEP_TIME);
for (i = 0; i<size; i++) {
pthread_join(car[i], NULL);
}
// pthread_join(check, NULL);
}
int main() {
initialize(); //初始化
int num[100];
char s[100];
int i;
scanf("%s", s); //读取输入
int len = strlen(s);
for (i = 0; i<len; i++) num[i] = i + 1;
//创建车辆线程
for (i = 0; i<len; i++) {
switch (s[i]) {
case 'w': {
is_car[W] = 1;
push(W,num[i]);
pthread_create(&thread_id[W][rear[W]], NULL, car_from_west, NULL);
car[size++] = thread_id[W][rear[W]];
break;
}
case 'e': {
is_car[E] = 1;
push(E,num[i]);
pthread_create(&thread_id[E][rear[E]], NULL, car_from_east, NULL);
car[size++] = thread_id[E][rear[E]];
break;
}
case 's': {
is_car[S] = 1;
push(S,num[i]);
pthread_create(&thread_id[S][rear[S]], NULL, car_from_south, NULL);
car[size++] = thread_id[S][rear[S]];
break;
}
case 'n': {
is_car[N] = 1;
push(N,num[i]);
pthread_create(&thread_id[N][rear[N]], NULL, car_from_north, NULL);
car[size] = thread_id[N][rear[N]];
size++;
break;
}
}
}
//创建死锁检测线程
pthread_create(&check, NULL, check_dead_lock, NULL);
//等待进程结束
thread_wait();
}
开小车
最新推荐文章于 2025-02-17 17:30:29 发布