您好,登錄后才能下訂單哦!
線程的同步與互斥
多個線程同時訪問共享數據時可能會發生沖突,比如兩個線程同時把一個全局變量加1,結果可能不是我們所期待的:
我們看這段代碼的執行結果:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
static int g_count=0;
void *thread(void *arg)
{
int index=0;
int tmp=0;
while(index++<5000)
{
tmp=g_count;
printf("this is thread %d,count is :%d\n",(int)arg,tmp);
g_count=tmp+1;
}
}
int main()
{
pthread_t tid1,tid2;
pthread_create(&tid1,NULL,thread,(void*)1);
pthread_create(&tid2,NULL,thread,(void*)2);
pthread_join(tid1,NULL);
pthread_join(tid2,NULL);
printf("the final value is %d\n",g_count);
return 0;
}
我們看它的執行結果:
我們創建了兩個線程,各自把全局變量g_count加了5000次,結果理論上應該是10000,但其實不然,每次運行的結果都不一樣,證明訪問沖突了。為了解決這個問題,我們需引入互斥鎖。獲得鎖的線程可以完成“讀--修改--寫”的操作,然后釋放鎖給其他線程,沒有獲得鎖的線程只能等待,而不能訪問共享數據,這樣“讀--修改--寫”散步操作就成了原子操作,要么都執行,要么都不執行,不會執行到中間而被打斷,這樣就如我們所期待的了。
pthread_mutex_init函數對mutex做初始化,它可以被pthread_mutex_destroy銷毀。如果mutex變量是靜態分配的,也可以用宏定義PTHREAD_MUTEX_INITIALIZER來初始化,相當于pthread_mutex_init初始化并且attr參數為NULL。
加鎖和解鎖所需函數:
int pthread_mutex_lock(pthread_mutex_t *mutex)
int pthread_mutex_trylock(pthread_mutex_t *mutex)
int pthread_mutex_unlock(pthread_mutex_t *mutex)
成功返回0,失敗返回錯誤號。
一個線程可以調用int pthread_mutex_lock獲得mutex,如果這時候另一個線程已經調用int pthread_mutex_lock獲得了該mutex,則當前線程需要掛起等待,直到另一個線程調用pthread_mutex_unlock釋放mutex,當前線程被喚醒,才能獲得該mutex并繼續執行。
如果一個線程既想獲得鎖,又不想掛起等待,可以調用 pthread_mutex_trylock,如果mutex已經被另一個線程獲得,則這個函數會返回EBUSY,而不會使線程掛起等待。
知道這些的話,我們重新修改以上代碼:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
static int g_count=0;
pthread_mutex_t mutex_lock=PTHREAD_MUTEX_INITIALIZER;
void *thread(void *arg)
{
int index=0;
int tmp=0;
while(index++<5000)
{
pthread_mutex_lock(&mutex_lock);
tmp=g_count;
printf("this is thread %d,count is :%d\n",(int)arg,tmp);
g_count=tmp+1;
pthread_mutex_unlock(&mutex_lock);
}
}
int main()
{
pthread_t tid1,tid2;
pthread_create(&tid1,NULL,thread,(void*)1);
pthread_create(&tid2,NULL,thread,(void*)2);
pthread_join(tid1,NULL);
pthread_join(tid2,NULL);
printf("the final value is %d\n",g_count);
return 0;
}
運行結果如下:
我們可以看到,經過我們加鎖后,最后value的值是我們所期待的10000,加鎖成功,成功實現了兩個線程的互斥運行。
死鎖產生的原因及四個必要條件
所謂死鎖,是指多個進程在運行過程中因爭奪資源而造成的一種僵局,當進程處于這種僵持狀態時,若無外力作用,他們都將無法再向前推進。
產生死鎖的主要原因有:
1.系統資源不足;
2.進程運行推進的順序不合適;
3.資源分配不當等;
如果系統資源充足,進程的資源請求都能夠得到滿足,死鎖出現的可能性就降低,否則,就會因爭奪有限的資源而陷入死鎖。其次,進程運行推進順序與速度不同,也可能產生死鎖。
產生死鎖的四個必要條件:
1.互斥條件:一個資源每次只能被一個進程使用;
2.請求與保持條件:一個進程因請求資源而阻塞時,對已獲得的資源保持不放;
3.不剝奪條件:進程已獲得的資源,在使用完之前,不能強行剝奪;
4.循環等待條件:若干進程之間形成一種頭尾相接的循環等待資源關系;
以上是產生死鎖的四個必要條件,只要系統發生死鎖,這些條件必然成立,而只要上述條件之一不滿足,就不會發生死鎖。
處理死鎖的基本方法:
1.預防死鎖:
該方法是通過設置某些限制條件,去破壞產生死鎖四個必要條件中的一個或幾個條件,來預防發生死鎖。
2.避免死鎖
不需事先采取各種限制措施去破壞產生死鎖的四個必要條件,而是在資源的動態分配過程中,用某種方法去防止系統進入不安全狀態,從而避免發生死鎖。
3.檢測死鎖
這種方法不需事先采取任何限制措施,也不必檢查系統是否已經進入不安全區,而是允許系統在運行過程中發生死鎖。但可以通過系統所設置的檢測機構,及時的檢測死鎖的發生,并精確的確定與死鎖有關的進程資源,然后采取適當措施,從系統中將已發生的死鎖清除掉。
4.解除死鎖
這是與檢測死鎖相配套的一種措施。當檢測到發生死鎖時,需將進程從死鎖狀態中解脫出來。常用的實施方法是撤消或掛起一些進程,以便回收一些資源,再將這些資源分配給已處于阻塞狀態的進程,使之轉為就緒狀態,一邊繼續運行。
死鎖的解除與預防:
理解了死鎖的原因,尤其是產生死鎖的四個必要條件,就可以最大程度的避免,預防和解除死鎖。所以在系統設計,進程調度等方面注意如何不讓這四個必要條件成立,如何確定資源的合理分配算法,避免進程永久占用系統資源。此外,也要防止進程在處于等待狀態的情況下占用資源。因此,對資源的分配要給與合理的規劃。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。