死鎖四要素:?
?互斥條件: 至少有一個資源不能共享加袋,即一次只能被一個進程/線程占用 ??
?占用和等待: ?一個進程/線程持有資源A并且等待其他進程釋放資源B。 ?
? 非搶占: 一個進程/線程不能無緣無故從另一個進程/線程搶占資源薄扁,只能等待其使用完資源之后自動釋放 ? ?
??循環(huán)等待: 一組進程/線程形成一種循環(huán)等待資源的關(guān)系。每個進程/線程都在等待下一個進程/線程所持有的資源废累。 ? ? ??
????避免死鎖只要破壞上面任何一個條件即可邓梅。
哲學(xué)家進餐問題描述:
?哲學(xué)家進餐問題是一個經(jīng)典的并發(fā)編程問題,描述了五位哲學(xué)家圍坐在圓桌前九默,每人面前放著一碗意大利面和一只叉子震放。他們只有在兩只叉子都拿到手才能吃意大利面,吃完后才能放下叉子繼續(xù)思考驼修。問題是如何設(shè)計算法殿遂,使得哲學(xué)家們能夠正確地進餐而不發(fā)生死鎖(每個哲學(xué)家都在等待右邊的叉子)或饑餓(某些哲學(xué)家始終無法拿到叉子)的情況。
? 方案一: 限制同時吃飯人數(shù)避免死鎖乙各,對應(yīng)打破死鎖的循環(huán)等待這個必要條件墨礁。
? ?為什么限制同時吃飯人數(shù)可以避免死鎖?
? ?根據(jù)抽屜原理: ?K = N * (R) + 1 // K 是資源數(shù)耳峦, N 進程數(shù)恩静,R 是每個進程需要獲取的資源數(shù)量
? ?資源數(shù)量大于需求數(shù)量,必然有一個哲學(xué)家可以拿到2個筷子進餐。打破死鎖必要條件:循環(huán)等待(壓根不用循環(huán))
????哲學(xué)家問題 K = 5 驶乾,R = 1 得出 N = 4邑飒,即同時允許四個哲學(xué)家線程用餐, 至于能否用餐還是看筷子的互斥鎖。
? ? 主要代碼實現(xiàn):
pthread_mutex_t forks[NUM_PHILOSOPHERS]; //每個叉子資源訪問的互斥鎖
sem_t *max_philosophers; //限制同時最多哲學(xué)家進餐人數(shù)
//最多支持NUM_PHILOSOPHERS - 1,個人用餐级乐,抽屜原理可知 最少有一個人手上會拿到兩把叉子 max_philosophers = sem_open("max_philosophers", O_CREAT | O_EXCL, 0666, NUM_PHILOSOPHERS - 1);
static void *philosopher(void *arg) {
? ? int i = *(int *)arg; //當(dāng)前哲學(xué)家編號
? ? int leftFork = (i + NUM_PHILOSOPHERS - 1) % NUM_PHILOSOPHERS;
? ? int rightFork = (i + 1) % NUM_PHILOSOPHERS;
? ? while (1)
? ? {
? ? ? ? sem_wait(max_philosophers);
? ? ? ? printf("Philosopher %d is thinking.\n", i);
? ? ? ? pthread_mutex_lock(&forks[leftFork]);
? ? ? ? pthread_mutex_lock(&forks[rightFork]);
? ? ? ? printf("Philosopher %d is eating.\n", i);
? ? ? ? sleep(1);
? ? ? ? pthread_mutex_unlock(&forks[leftFork]);
? ? ? ? pthread_mutex_unlock(&forks[rightFork]);
? ? ? ? sem_post(max_philosophers);
? ? ? ? sleep(1);
? ? }
? ? return NULL;
}
方案二: 根據(jù)哲學(xué)家編碼奇偶按照不同順序獲取不同的筷子. 打破互斥和循環(huán)條件疙咸,搶占和等待條件也占了點邊。
主要代碼:
#define NUM_PHILOSOPHERS 5
pthread_mutex_t forks[NUM_PHILOSOPHERS]; //叉子的互斥鎖
//拿起筷子
void pickup_forks(int leftfork, int rightfork, int philosopher_id) {
? ? pthread_mutex_lock(&forks[leftfork]);
? ? pthread_mutex_lock(&forks[rightfork]);
? ? printf("Philosopher %d is eating.\n", philosopher_id);
}
//放下筷子
void return_forks(int leftfork, int rightfork) {
? ? pthread_mutex_unlock(&forks[leftfork]);
? ? pthread_mutex_unlock(&forks[rightfork]);
}
static void *philosopher(void *arg) {
? ? int i = *(int *)arg;
? ? int leftfork = (i + NUM_PHILOSOPHERS - 1) % NUM_PHILOSOPHERS;
? ? int rightfork = (i + 1) % NUM_PHILOSOPHERS;
? ? while (1)
? ? {
? ? ? ? if (i % 2 == 0) {
? ? ? ? ? ? pickup_forks(leftfork, rightfork, i);
? ? ? ? } else {
? ? ? ? ? ? pickup_forks(rightfork, leftfork, i);
? ? ? ? }
? ? ? ? sleep(1);
? ? ? ? return_forks(leftfork, rightfork);
? ? ? ? sleep(1);
? ? }
? ? return NULL;
}
非搶占 條件就不舉例了:
????因為一旦涉及到非搶占风科,必然會引入線程優(yōu)先級的問題撒轮,比如A哲學(xué)家的線程優(yōu)先級高但是資源被優(yōu)先級低的B哲學(xué)家線程搶占,那么系統(tǒng)調(diào)度會讓B釋放,讓給A贼穆。如果A頻繁的吃题山,B 線程哲學(xué)家總有一天會被餓死。A 也會被活活撐死故痊。顶瞳。。
吸煙者問題描述:
?三個吸煙者在一個房間內(nèi)崖蜜,還有一個香煙供應(yīng)者浊仆。為了制造并抽掉香煙,每個吸煙者需要三樣?xùn)|西:煙草豫领、紙和火柴抡柿,供應(yīng)者有豐富貨物提供。 三個吸煙者中等恐,第一個有自己的煙草洲劣,第二個有自己的紙,第三個有自己的火柴课蔬。 供應(yīng)者隨機地將兩樣不同的東西放在桌子上囱稽,允許一個吸煙者進行對健康不利的吸煙。 當(dāng)吸煙者完成吸煙后喚醒供應(yīng)者二跋,供應(yīng)者再隨機地把兩樣不同的東西放在桌子上战惊,喚醒一個吸煙者。
這里核心問題就是一個: 當(dāng)前抽煙者手里拿的資源扎即,然后這個資源準(zhǔn)備好之后吞获,讓供應(yīng)者釋放資源信號。所以互斥的信號量是當(dāng)前抽煙人手里的資源谚鄙,而不是另外兩種資源各拷。當(dāng)初看這個問題時候總是會被另外兩個資源印象。這個思路是不對的
代理商放資源需要抽煙者線程激活闷营。抽煙者線程也靠代理商當(dāng)前手里的資源激活烤黍,形成互斥。
吸煙者問題 理解之后實現(xiàn)比較簡單,代碼就不貼了速蕊。有興直接去翻源碼即可嫂丙。