天天看點

線程同步與互斥及死鎖問題

線程我們之前已經總結過了,就是程序的一個執行分支。既然是一個執行分支,那麼我們就可以定義兩個線程,在定義一個全局變量,初始值置為0,讓這兩個線程,同時對這個全局變量進行++處理,1000次,100000次,100000000次,之後,你會發現,數值越大,你得到想要的結果的幾率就越小。這是為什麼呢?

這個全局變量可以被這兩個線程同時看見,那麼他就是臨界資源了,但是線程對臨界資源通路,卻不原子性的,那麼出錯就難免的了

還有就是線程間的切換,也可能導緻錯誤。

那麼怎麼解決呢?

既然它們的通路不是原子性的,那麼保證原子性就行了。還記得互斥嗎?互斥說的是:在任意時刻,隻有一個執行流通路臨界區。

我們對臨界資源上把鎖——互斥鎖,來解決這個問題:

互斥鎖的建立和銷毀:

pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
 int pthread_mutex_destroy(pthread_mutex_t *mutex);
           

加鎖和解鎖:

int pthread_mutex_lock(pthread_mutex_t *mutex)//加鎖
int pthread_mutex_trylock(pthread_mutex_t *mutex)//加鎖
int pthread_mutex_unlock(pthread_mutex_t *mutex)//解鎖
           

這裡有兩種加鎖的函數,那麼他們有什麼差別呢?第一個函數,去申請資源,如果沒有資源,那麼會一直等,知道有資源;而第二個函數,如果沒有申請到資源,那麼會隔段時間問問,有沒有資源,可以說成:輪詢

加鎖之後,那麼線程就變成串行的了,雖然保證了原子性,不過線程的優點就發揮不出來了。

互斥鎖和二進制信号量在理論上是差不多的。不過,一個用于線程,一個用于程序

互斥鎖可以被多個線程同時申請,那麼互斥鎖同樣也是臨界資源,既然是臨界資源,那麼如果兩個或多個線程同時争奪這個鎖 ,怎麼辦,這就是死鎖。

死鎖的概念: 是指兩個或兩個以上的程序(線程)在執行過程中,因争奪資源而造成的一種互相等待的現象,若無外部處理作用,它們都将無限等待下去。

死鎖形成原因:

1、系統資源不足;

2、程序(線程)推進的順序不恰當;

3、資源配置設定不當。

死鎖的形成場景:

1、忘記釋放鎖:在申請鎖和釋放鎖之間直接return

2、單線程重複申請鎖:一個線程,剛出臨界區,又去申請資源。

3、多線程多鎖申請:兩個線程,兩個鎖,他們都已經申請了一個鎖了,都想申請對方的鎖

4、環形鎖的申請:多個線程申請鎖的順序形成互相依賴的環形

死鎖産生的必要條件 :

1、互斥條件:指程序對所配置設定到的資源進行排它性使用,即在一段時間内某資源隻由一個程序占用。如果此時還有其它程序請求資源,則請求者隻能等待,直至占有資源的程序用完釋放。

2、請求和保持條件:指程序已經保持至少一個資源,但又提出了新的資源請求,而該資源已被其它程序占有,此時請求程序阻塞,但又對自己已獲得的其它資源保持不放。

3、不可搶占條件:指程序已獲得的資源,在未使用完之前,不能被剝奪,隻能在使用完時由自己釋放。

4、環路等待條件:指在發生死鎖時,必然存在一個程序——資源的環形鍊,即程序集合{P0,P1,P2,···,Pn}中的P0正在等待一個P1占用的資源;P1正在等待P2占用的資源,……,Pn正在等待已被P0占用的資源。

處理死鎖的方法:

1、預防死鎖:可以破壞産生死鎖的必要條件:破壞“請求和保持”條件;破壞“不可搶占”條件;破壞“循環等待”條件

2、避免死鎖:銀行家算法

算法原理:把作業系統看作是銀行家,作業系統管理的資源相當于銀行家管理的資金,程序向作業系統請求配置設定資源相當于使用者向銀行家貸款。為保證資金的安全,銀行家規定:

(1) 當一個顧客對資金的最大需求量不超過銀行家現有的資金時就可接納該顧客;

(2) 顧客可以分期貸款,但貸款的總數不能超過最大需求量;

(3) 當銀行家現有的資金不能滿足顧客尚需的貸款數額時,對顧客的貸款可推遲支付,但總能使顧客在有限的時間裡得到貸款;

(4) 當顧客得到所需的全部資金後,一定能在有限的時間裡歸還所有的資金.

算法:

設程序cusneed提出請求REQUEST [i],則銀行家算法按如下規則進行判斷。

(1)如果REQUEST [cusneed]

(2)如果REQUEST [cusneed] [i]<= AVAILABLE[i],則轉(3);否則,等待。

(3)系統試探配置設定資源,修改相關資料:

AVAILABLE[i]-=REQUEST[cusneed][i];

ALLOCATION[cusneed][i]+=REQUEST[cusneed][i];

NEED[cusneed][i]-=REQUEST[cusneed][i];

(4)系統執行安全性檢查,如安全,則配置設定成立;否則試探險性配置設定廢棄,系統恢複原狀,程序等待。

3、檢驗死鎖和解除死鎖:

先檢測:這種方法并不須事先采取任何限制性措施,也不必檢查系統是否已經進入不安全區,此方法允許系統在運作過程中發生死鎖。但可通過系統所設定的檢測機構,及時地檢測出死鎖的發生,并精确地确定與死鎖有關的程序和資源。檢測方法包括定時檢測、效率低時檢測、程序等待時檢測等;

然後解除死鎖:采取适當措施,從系統中将已發生的死鎖清除掉。

繼續閱讀