2018/12/24

Delphi in Depth. Windows Message vs Thread.

程式很忙


同事最近遇到程式運作流程不如預想的情形,來找我幫忙解決。

研究程式碼的過程中,發現他用到大量的 PostMessage / SendMessage,這是相當有趣的走向,同事解說是在於在 Event call Event 時,有時會因為 UI 刷新造成互相干擾進而發生例外,所以才這樣寫。

PostMessage 和 SendMessage 兩者差異說明如下:
Non Blocking 和 Blocking,也等同 Asynchronous (非同步) 和 Synchronous (同步) 的關係。

PostMessage 的場合:主程式 (Main Thread) 執行到此句時會把 Message 放進 Message Queue 裡 (可以視為 Sub Thread) 依序排好,等待 Main Thread Idle 時才會把 Message Queue 依序派送到主程式的對應函式處理。

程式流程如下:
Delphi 的程式執行順序:PostMessage

可以看到 Button1Click 事件結束後,才會從 OnMyMessage 函式進入。



SendMessage 的場合:主程式 (Main Thread) 執行到此句時,會把 Message 直接派送到主程式的對應函式處理,並等待該函式執行完畢後,再回到  Main Thread 執行後續程式碼。

程式流程如下:
Delphi 的程式執行順序:SendMessage

由圖可知,在 SendMessage 執行後,會先執行 OnMyMessage 函式,等 OnMyMessage 函式完成後才會完成整個 Button1Click 事件。


這樣的程式碼寫久了,一直沒有問題,但就是 Debug 時麻煩了點:
  1. 找到 PostMessage / SendMessage 之處。
  2. 找到 Message 對應函式。
  3. 進入該函式下中斷點進行 Debug 。


難道沒有更好的方法了嗎?




答案是有的!

在 Delphi XE (2011) 後,Thread 多了 CreateAnonymousThread 和 Synchronous 這兩支 Class function,也就對應上 PostMessage / SendMessage 功能。

來看看程式是怎麼寫的吧!

  • 對應 PostMessage 的實作法:


答案會得到:
Main Thread Msg.
Message Msg.


  • 對應 SendMessage 的實作法:


答案會得到:
Message Msg.
Main Thread Msg.

使用 TThread class 方法還有適合跨平台這個好處,值得一學的小技巧。

PostMessage / SendMessage 則可以專注在 Windows 上跨 Process 的互動。

至於 非同步 / 同步 這樣的小事,就交給 TThread class 方法吧!

See also:

沒有留言:

張貼留言