2016-02-22 81 views
0

如果我使用SendMessage()從不同線程到一個接收器會發生什麼?想象一下,接收者仍在處理來自Thread1的消息,並且Thread2發送另一個消息(使用SendMessage())的情況。接收端會發生什麼?是否停止執行Message1,處理Message2,並在Message2返回Message1後返回?或者Message2等待Message1的結束?使用SendMessage()多線程

+0

如果代碼進入可更改的等待狀態(這將允許Message2進行處理),Message1將在該處理期間被搶佔。所以消息處理的順序和原子性不能保證。 –

+1

當線程調用消息處理函數時,調度第二條消息。 –

回答

3

的基本規則是:唯一的時間線程分派跨線程發送的消息是,要求該線程的消息檢索功能(GetMessagePeekMessage等)時。消息檢索函數首先檢查任何跨線程發送的消息,一個接一個地發送消息,然後繼續從線程的消息隊列中檢索消息。

這具有2個後果:

  • 跨線程發送的消息被分派,當接收線程沒有處理1)任何排隊的消息。
  • 發送跨線程發送的消息,當接收線程不處理時1)任何其他跨線程發送的消息。

在您的具體示例中,接收方將繼續處理Message1直到完成,然後繼續在下一次調用Message2時調用Message2 retrieval函數。

這條規則有一個值得注意的例外:等待SendMessage返回的線程可以調度進入的跨線程發送的消息2)。這意味着有可能重新進入。再次舉一個例子,假設Message1在某個點的消息處理程序調用SendMessage,很可能是在Message1繼續處理之前分派Message2。

概括起來:

  • 跨線程發送的郵件接收線程連續調度。
  • 線程分派跨線程發送的消息時,有幾個明確定義的時間。
  • 雖然跨線程發送的消息永遠不會併發處理,但沒有原子性規則;準備重新入住。


1)假設主叫的消息檢索功能不正常的消息處理的一部分。
2)有關爲什麼會出現這種情況的詳細信息,請參見 When can a thread receive window messages?

1

我假定問題是關於消息被髮送到特定的窗口,即非NULL或HWND_BROADCAST的HWND,並且該窗口屬於同一進程的線程。

在這種情況下,創建目標窗口的線程將在下次使用包含給定窗口的過濾器調用GetMessage時接收消息。發送線程將被阻塞,直到接收線程實際完成消息的處理。

如果在處理來自Thread1的消息時,接收線程再次調用GetMessage/DispatchMessage,那麼任何待處理的消息(包括可能由Thread2發送的消息)將在該點處理,則控制將返回到處理消息來自Thread1。

從文檔的SendMessage function

如果指定的窗口是通過調用線程創建的窗口過程立即作爲子程序調用。如果指定的窗口是由不同的線程創建的,則系統切換到該線程並調用相應的窗口過程。僅當接收線程執行消息檢索代碼時才處理線程之間發送的消息。發送線程被阻塞,直到接收線程處理消息。

+0

我一直髮現這個'切換到那個線程'聲明有爭議。事實是,它沒有:它從事帽子接下來描述,這不是任何意義上的線程切換,而是某種類型的塊和帖子。 – EJP

+0

@EJP對,就像措辭那樣有點誤導,最終效果就是你所描述的。 FWIW的引用直接來自官方的MSDN文檔,並且(在快速檢查中)至少自2001年以來沒有改變。 – dxiv