C語言實戰——哲學家問題

C語言實戰——哲學家問題

問題描述

有五個哲學家繞着圓桌坐,每個哲學家面前有一盤面,兩人之間有一支筷子,這樣每個哲學家左右各有一支筷子。哲學家有2個狀態,思考或者拿起筷子喫飯。如果哲學家拿到一隻筷子,不能喫飯,直到拿到2只才能喫飯,並且一次只能拿起身邊的一支筷子。一旦拿起便不會放下筷子直到把飯喫完,此時才把這雙筷子放回原處。如果,很不幸地,每個哲學家拿起他或她左邊的筷子,那麼就沒有人可以喫到飯了。
哲學家進餐問題是一個多線程運用的經典例子,涉及到線程同步/互斥,臨界區訪問問題以及死鎖問題。

解決方法

方法一

  • 通過互斥信號量mutex對哲學家進餐之前取左右兩側的筷子的操作進行保護,可以防止死鎖的出現
  • 也就是說,要達到的目的是,某位哲學家開始拿第一支筷子時,其他哲學家全部不準拿筷子(即使他已經餓了),只可以放下,直到這位哲學家拿到一雙筷子之後,允許其他筷子被拿起,以此類推。
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <time.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
 
#define N 5
 
sem_t chopsticks[N];//設置5種信號量,有5種不同類型的資源,每一種有1個,這樣便於理解,因爲每個哲學家需要的資源不同
 
pthread_mutex_t mutex;//定義互斥鎖
 
int philosophers[N] = {0, 1, 2, 3, 4};//代表5個哲學家的編號
 
void delay (int len) 
{
	int i = rand() % len;
	int x;
	while (i > 0) 
	{
		x = rand() % len;
		while (x > 0) 
		{
			x--;
		}
		i--;
	}
}
 
void *philosopher (void* arg) 
{
	int i = *(int *)arg;
	int left = i;//左筷子的編號和哲學家的編號相同
	int right = (i + 1) % N;//右筷子的編號爲哲學家編號+1
	while (1) 
	{
		printf("哲學家%d正在思考問題\n", i);
		delay(60000);
		
		printf("哲學家%d餓了\n", i);
 
		pthread_mutex_lock(&mutex);//加鎖
 
		sem_wait(&chopsticks[left]);//此時這個哲學家左筷子的信號量-1之後>=0時,表示能繼續執行。
		printf("哲學家%d拿起了%d號筷子,現在只有一支筷子,不能進餐\n", i, left);
		sem_wait(&chopsticks[right]);
		printf("哲學家%d拿起了%d號筷子\n", i, right);
 
		pthread_mutex_unlock(&mutex);//解鎖
 
		printf("哲學家%d現在有兩支筷子,開始進餐\n", i);
		delay(60000);
		sem_post(&chopsticks[left]);
		printf("哲學家%d放下了%d號筷子\n", i, left);
		sem_post(&chopsticks[right]);
		printf("哲學家%d放下了%d號筷子\n", i, right);
	}
}
 
int main (int argc, char **argv) 
{
	srand(time(NULL));
	pthread_t philo[N];
	
	//信號量初始化
	for (int i=0; i<N; i++) 
	{
		sem_init(&chopsticks[i], 0, 1);
	}
 
	pthread_mutex_init(&mutex,NULL);//初始化互斥鎖
	
	//創建線程
	for (int i=0; i<N; i++) 
	{
		pthread_create(&philo[i], NULL, philosopher, &philosophers[i]);
	}
	
	//掛起線程
	for (int i=0; i<N; i++) 
	{
		pthread_join(philo[i], NULL);
	}
	
	//銷燬信號量
	for (int i=0; i<N; i++) 
	{
		sem_destroy(&chopsticks[i]);
	}
 
	pthread_mutex_destroy(&mutex);//銷燬互斥鎖
 
	return 0;
}

方法二

  • 對他們的拿筷子的順序進行規定
  • 規定奇數號哲學家先拿左筷子再拿右筷子,而偶數號哲學家相反。所以將是 2,3 號哲學家競爭 3 號筷子,4,5 號哲學家競爭 5 號筷子。1 號哲學家不需要競爭。最後總會有一個哲學家能獲得兩支筷子而進餐。
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <time.h>
#include <unistd.h>
#include <pthread.h>
#include <semaphore.h>
 
#define N 5
 
sem_t chopsticks[N];//設置5種信號量,有5種不同類型的資源,每一種有1個,這樣便於理解,因爲每個哲學家需要的資源不同
 
int philosophers[N] = {0, 1, 2, 3, 4};//代表5個哲學家的編號
 
void delay (int len) 
{
	int i = rand() % len;
	int x;
	while (i > 0) 
	{
		x = rand() % len;
		while (x > 0) 
		{
			x--;
		}
		i--;
	}
}
 
void *philosopher (void* arg) 
{
	int i = *(int *)arg;
	int left = i;//左筷子的編號和哲學家的編號相同
	int right = (i + 1) % N;//右筷子的編號爲哲學家編號+1
	while (1) {
		if(i % 2 == 0){
		printf("哲學家%d正在思考問題\n", i);
		delay(60000);
		
		printf("哲學家%d餓了\n", i);
		sem_wait(&chopsticks[right]);//此時這個哲學家左筷子的信號量-1之後>=0時,表示能繼續執行。
		printf("哲學家%d拿起了%d號筷子,現在只有一支筷子,不能進餐\n", i, right);
		sem_wait(&chopsticks[left]);
		printf("哲學家%d拿起了%d號筷子, 現在有兩支筷子,開始進餐\n", i, left);
		delay(60000);
		sem_post(&chopsticks[left]);
		printf("哲學家%d放下了%d號筷子\n", i, left);
		sem_post(&chopsticks[right]);
		printf("哲學家%d放下了%d號筷子\n", i, right);
		}
 
		else{
			printf("哲學家%d正在思考問題\n", i);
			delay(60000);
			
			printf("哲學家%d餓了\n", i);
			sem_wait(&chopsticks[left]);//此時這個哲學家左筷子的信號量-1之後>=0時,表示能繼續執行。
			printf("哲學家%d拿起了%d號筷子,現在只有一支筷子,不能進餐\n", i, left);
			sem_wait(&chopsticks[right]);
			printf("哲學家%d拿起了%d號筷子, 現在有兩支筷子,開始進餐\n", i, right);
			delay(60000);
			sem_post(&chopsticks[left]);
			printf("哲學家%d放下了%d號筷子\n", i, left);
			sem_post(&chopsticks[right]);
			printf("哲學家%d放下了%d號筷子\n", i, right);
		}
	}
}
 
int main (int argc, char **argv) 
{
	srand(time(NULL));
	pthread_t philo[N];
	
	//信號量初始化
	for (int i=0; i<N; i++) 
	{
		sem_init(&chopsticks[i], 0, 1);
	}
	
	//創建線程
	for (int i=0; i<N; i++) 
	{
		pthread_create(&philo[i], NULL, philosopher, &philosophers[i]);
	}
	
	//掛起線程
	for (int i=0; i<N; i++) 
	{
		pthread_join(philo[i], NULL);
	}
	
	//銷燬信號量
	for (int i=0; i<N; i++) 
	{
		sem_destroy(&chopsticks[i]);
	}
 
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章