轉載鏈接:https://blog.csdn.net/hj605635529/article/details/73064877
有五個哲學家公用一張餐桌,分別坐在周圍的五張椅子上,在餐桌上有五個碗和五隻筷子,他們的生活方式是交替地進行思考和用餐。平時,一個哲學家進行思考,飢餓時便試圖拿取其左右最靠近他的筷子,只有在他拿到兩隻筷子時才能進餐,進餐完畢,放下筷子繼續思考。
思路:
選用互斥鎖mutex,如創建5個, pthread_mutex_t m[5];
模型抽象:
5個哲學家 --> 5個線程; 5支筷子 --> 5把互斥鎖 int left(左手), right(右手)
5個哲學家使用相同的邏輯,可通用一個線程主函數,void *tfn(void *arg),使用參數來表示線程編號:int i = (int)arg;
哲學家線程根據編號知道自己是第幾個哲學家,而後選定鎖,鎖住,喫飯。否則哲學家thinking。
A B C D E
5支筷子,在邏輯上形成環: 0 1 2 3 4 分別對應5個哲學家:
所以有:
if(i == 4)
left = i, right = 0;
else
left = i, right = i+1;
振盪:如果每個人都攥着自己左手的鎖,嘗試去拿右手鎖,拿不到則將鎖釋放。過會兒五個人又同時再攥着左手鎖嘗試拿右手鎖,依然拿不到。如此往復形成另外一種極端死鎖的現象——振盪。
避免振盪現象:只需5個人中,任意一個人,拿鎖的方向與其他人相逆即可(如:E,原來:左:4,右:0 現在:左:0, 右:4)。
所以以上if else語句應改爲:
if(i == 4)
left = 0, right = i;
else
left = i, right = i+1;
而後, 首先應讓哲學家嘗試加左手鎖:
while {
pthread_mutex_lock(&m[left]); 如果加鎖成功,函數返回再加右手鎖,
如果失敗,應立即釋放左手鎖,等待。
若,左右手都加鎖成功 --> 喫 --> 喫完 --> 釋放鎖(應先釋放右手、再釋放左手,是加鎖順序的逆序)
}
主線程(main)中,初始化5把鎖,銷燬5把鎖,創建5個線程(並將i傳遞給線程主函數),回收5個線程。
避免死鎖的方法:
- 當得不到所有所需資源時,放棄已經獲得的資源,等待。
- 保證資源的獲取順序,要求每個線程獲取資源的順序一致。如:A獲取順序1、2、3;B順序應也是1、2、3。若B爲3、2、1則易出現死鎖現象。
代碼:
#include<stdio.h>
#include<unistd.h>
#include<pthread.h>
#include<stdlib.h>
pthread_mutex_t chopstick[5]; //5把鎖,也就是5根筷子。
void*tfn(void *arg)
{
int i = (int)arg;
int left,right; //左右筷子的編號。
if(i == 4)
{
left = 0;
right = i;
}
else
{
left = i;
right = i+1;
}
while(1)
{
sleep(1); //思考
pthread_mutex_lock(&chopstick[left]); //拿到左手的筷子。
printf("philosopher %d fetches chopstick %d\n",i,left);
if(pthread_mutex_trylock(&chopstick[right]) != 0 )//拿右手的筷子失敗
{
pthread_mutex_unlock(&chopstick[left]); //右手筷子被拿走,放下左手的筷子。
continue;
}
printf("philosopher %d fetches chopstick %d\n",i,right);
printf("philosopher %d is eating.\n",i);
sleep(2); //喫飯
pthread_mutex_unlock(&chopstick[right]); //放下右手的筷子。
printf("philosopher %d release chopstick %d\n",i,right);
pthread_mutex_unlock(&chopstick[left]); //放下右手的筷子。
printf("philosopher %d release chopstick %d\n",i,left);
}
}
int main()
{
pthread_t tid[5]; //5個哲學家
int i ;
for(i = 0; i < 5; ++i)
{
pthread_mutex_init(&chopstick[i],NULL);
pthread_create(&tid[i],NULL,tfn,(void*)i);
}
for( i = 0; i < 5; ++i)
{
pthread_join(tid[i],NULL);
}
return 0;
}