併發編程之臨界區\阻塞\非阻塞\死鎖\飢餓\活鎖

本文介紹併發編程中的若干概念,實際上在筆者之前的文章中,已經介紹過很多概念。比如:併發與並行、同步與異步、鎖與信號量等等。參考《併發編程專欄》,本文計息介紹一些相對深入一些的概念

一、臨界區

爲了方便大家理解,我們先看下面的這樣一張圖,我們可以把房子看作一個進程,每個房子裏面的住戶及其活動看作一個線程,飲水機、健身器材、廁所都屬於共享資源。這裏的共享資源實際就是臨界區的概念,臨界區的資源在同一時間只能被一個線程(住戶)使用,所以一旦臨界資源被佔用,其他的線程(住戶)能做的就只有等待。

比如,在一個出租房內,住戶A佔用了廁所,在他使用廁所的這段時間內廁所這個資源就是他獨佔的。如果住戶B此時也想上廁所,就只能等待住戶A上完廁所之後纔可以繼續使用該資源。

二、阻塞和非阻塞

瞭解了臨界區的概念之後,阻塞概念就好理解了。一個線程先佔用了臨界區的資源,此時如果其他的線程想使用臨界區資源就必須等待。這種佔用臨界區資源,阻塞其他線程繼續執行的情況就是線程阻塞(Blocking)。

然而說到非阻塞,一般說的就是是否對當前線程自己產生阻塞,比如:

  • 我執行一個任務,比如使用飲水機接水。我拿了一個杯子接水,而我必須在飲水機前面等着水接完,這種就是阻塞式線程。
  • 如果我拿了杯子接水,把杯子放到飲水機下面,飲水機會在杯子接滿水之後,自動對我發出異步通知(比如聲音告警)。我可以在此期間做其他的事情,這種就是非阻塞式線程(Non-Blocking)。非阻塞式線程,從編程的角度一般都是通過回調函數,或者響應式編程(Reactive programming)實現的。

三、死鎖、飢餓和活鎖

  • 死鎖:我們來看上面的這張圖,在十字路口A車道的A1車像轉向B車道,但B車道入口被B1車佔用;在十字路口B車道的B1車像轉向C車道,但C車道入口被C1車佔用;在十字路口C車道的C1車像轉向D車道,但D車道入口被D1車佔用;在十字路口D車道的D1車像轉向A車道,但A車道入口被A1車佔用;也就是說:線程因爲資源競爭,彼此需要資源又都無法釋放,導致線程無法獲取下一步執行所需的資源,導致死鎖產生。

  • 飢餓:舉個例子農民給小雞餵食,如果有五隻雞每次都剛好給五隻雞的飼料量。無法避免的是有的雞喫的量超過規劃量,最總導致某一隻雞無法喫到足夠的飼料。由於它無法遲到足夠的飼料,它就比較瘦弱,搶食的能力弱。惡性循環,最終很可能被餓死。具體到編程層面,就是某一線程A的優先級比較低,然後優先級高的線程又經常佔用資源不釋放,線程A長期無法得到有效執行,處於飢餓狀態。極端情況下,可能被餓死。

  • 活鎖:相對於死鎖和飢餓,活鎖是一種相對好的狀態。大家在生活中肯定遇到過這樣一種情況,你在樓梯拐角遇到一個同事,空間有限所以二人茬住了。你向左移動,你的同事也向左移動;你向右移動,你的同事也向右移動;所以你們兩個人都無法向前移動,這就是一個典型的活鎖。因爲人是高智慧的動物,又都懂得禮讓,所以對於人來說活鎖的問題很好解決,只要其中一個人原地不動,另一個人動一下就過去了。但是多線程面對活鎖的時候就沒有那麼智能了,有可能出現不斷地釋放資源(向左移)、佔用資源(向右移)的循環中,即使最終活鎖被解開,其資源開銷及時間成本都是很大的。

歡迎關注我的博客,更多精品知識合集

本文轉載註明出處(必須帶連接,不能只轉文字):字母哥博客 - zimug.com

覺得對您有幫助的話,幫我點贊、分享!您的支持是我不竭的創作動力!。另外,筆者最近一段時間輸出瞭如下的精品內容,期待您的關注。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章