線程間通信,包括線程同步,在指定線程中執行方法。
線程同步
其中線程同步通過C#本身提供的線程操作還是比較簡單的,注意使用互斥鎖,WaitHandle的使用可以滿足大部分的需求。(互斥鎖在不同線程中起作用,不會堵塞同線程的程序運行)。
在指定線程中執行方法
這種情況比較少見,一般都是窗體程序需要後臺進行運算,通過運算的結果對前臺界面進行更新。大多數情況下使用BackgroundWorker類和Task類可以滿足需求。但在極端的情況下可能還是需要自己去實現不同線程的方法執行。
C#本身的線程操作中不能直接做到在一個線程中讓另一個特定的線程運行方法,要完成這樣的操作,需要用到Windows的消息機制。使用下面的函數可以向指定ID的線程發送消息:
BOOL WINAPI PostThreadMessage( _In_ DWORD idThread, _In_ UINT Msg, _In_ WPARAM wParam, _In_ LPARAM lParam );在C#中可以用下面的方式引用方法
[DllImport("User32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool PostThreadMessage(int idThread, int Msg, IntPtr wParam, IntPtr lParam);
如果要向一個窗體的線程發送自定義消息,使用PostThreadMessage函數時會發現窗體無法接收到自己定義的消息。這是因爲窗體進程的標準消息循環只獲取對窗體發送的消息而PostThreadMessage只是指定了接收消息的線程ID,所以通過PostThreadMessage被過濾掉了。
如果接收消息的是有窗體的線程,可以用SendMessage函數向指定的窗體發送消息。
在必須指定線程ID的情況下,只能通過Hook來完成相關操作。
我選擇的是WH_GETMESSAGE類型的HOOK,回掉函數爲:
LRESULT CALLBACK GetMsgProc(
_In_ int code,
_In_ WPARAM wParam,
_In_ LPARAM lParam
);
其中 code 參數並不是消息的消息值。真正的消息值要通過lParam來獲得,lParam指向一個MSG結構。
同時一個相同的消息一般會被接收到2次,一次在消息還在消息隊列中時接收一次,另一次是消息從消息隊列中被移除。
通過wParam的值可以知道當前捕獲的消息是否在隊列中。