2010-10-20 118 views
16

我一直在閱讀多線程和共享資源訪問權限,其中一個(對我來說)新的概念是互斥鎖。我似乎無法找到的是線程實際發生的情況,發現「關鍵部分」被鎖定。它說在很多地方線程被「阻塞」了,但這是什麼意思?它是否被暫停,並且當鎖被解除後它會恢復嗎?或者是否會在「運行循環」的下一次迭代中再次嘗試?互斥鎖:「阻塞」是什麼意思?

我問的原因是因爲我想讓系統提供的事件(鼠標,鍵盤等)(在主線程中交付)在運行循環中非常特定的部分處理我的輔助線程。因此,無論發生什麼事件,我都會在自己的數據結構中排隊。顯然,數據結構需要互斥鎖,因爲它正在被兩個線程修改。缺少的難題是:在主線程中的某個函數中傳遞事件時會發生什麼,我想排隊,但隊列被鎖定?主線程是否會被暫停,或者它是否會跳過鎖定的部分並超出範圍(失去事件)?

回答

11

阻塞意味着執行卡在那裏;一般來說,系統會將線程置於睡眠狀態,並將處理器轉換爲另一個線程。當一個線程被阻塞試圖獲取一個互斥量時,當互斥量被釋放時,執行會恢復,儘管如果另一個線程在可能之前抓取互斥量,該線程可能會再次阻塞。

如果可能的話,通常會有一個try-lock操作來獲取互斥鎖,如果沒有的話,會返回一個錯誤。但是你最終將不得不將當前事件轉移到該隊列中。此外,如果您延遲將事件移至處理它們的線程,則無論如何,應用程序都將無響應。

實際上,一個隊列就是一種可以避免使用互斥鎖的情況。例如,Mac OS X(也可能是iOS)提供OSAtomicEnqueue()OSAtomicDequeue()函數(請參閱man atomic<libkern/OSAtomic.h>),這些函數利用處理器特定的原子操作來避免使用鎖定。

但是,爲什麼不直接在主線程上處理事件作爲主運行循環的一部分呢?

+0

主運行循環不驅動應用程序。我在Mac OSX上使用CVDisplayLink,它有效地產生了一個單獨的(高優先級)線程,這將反過來驅動我的運行循環。據我所知,事件將在主線程上傳遞,所以同步似乎是按順序的。 – zmippie 2010-10-21 09:21:56

1

阻擋意味着這一點。它被阻止。它不會繼續,直到有能力。你不會說你正在使用哪種語言,但大多數語言/庫都有鎖對象,你可以在這裏「嘗試」取鎖,然後根據你是否成功進行不同的操作。

但是,在例如Java同步塊中,您的線程將停止運行,直到它能夠獲取監視器(互斥鎖,鎖定)。 java.util.concurrent.locks.Lock接口描述了在鎖獲取方面具有更多靈活性的鎖對象。

6

想到它的最簡單方法是阻塞的線程處於等待(「睡眠」)狀態,直到線程釋放互斥鎖爲止。此時,操作系統將「喚醒」等待互斥體的線程之一,並讓它獲得並繼續。就好像操作系統只是將被阻塞的線程放在架子上,直到它具有它需要繼續的事情。在操作系統把線從架子上取下之前,它什麼也沒做。確切的實現 - 線程接下來要做什麼,無論它們是被喚醒還是排隊 - 都將取決於您的操作系統以及您正在使用的語言/框架。

+0

那麼究竟是被封鎖還是等待的區別,它們是同一回事嗎? – Celeritas 2014-10-05 22:26:08

0

太遲迴答,但我可以促進理解。我從實施的角度談論更多,而不是理論文章。

「阻塞」一詞是一種技術同義詞。人們可能會用它睡覺或僅僅等待。該術語必須在使用情況下加以理解。

阻塞是指等待 - 假設一個SMP系統中的線程A希望通過收購一些其他線程B.其作用機制之一是禁止搶佔,並保持在處理器上旋轉,除非乙得到它持有自旋鎖上。另一種機制可能是一個有效的機制,它允許其他線程使用處理器,以防B在容易的嘗試中無法獲得它。因此,我們安排線程B(作爲搶佔啓用)並將處理器交給其他線程C.在這種情況下,線程B只是在調度程序的隊列中等待,然後輪到它。理解B不是在等待,而是被動地等待,而不是等待忙碌的處理器週期。在BSD和Solaris系統上有像十字轉門這樣的數據結構來實現這種情況。

睡覺阻塞是指 - 如果線程B已而不是由系統調用像閱讀()從網絡套接字等待數據,它不能繼續,直到它得到它。因此,一些文本隨便使用術語阻塞爲「......阻止I/O」或「...阻止系統調用」。實際上,線程B寧可睡覺。有特定的數據結構被稱爲睡眠隊列 - 非常像空中港口上的豪華候車室:-)。當操作系統檢測到數據的可用性時,該線程將被喚醒,就像候診室的服務員一樣。