在
Invoke
或者
BeginInvoke
的使用中無一例外地使用了委托
Delegate
,至於委托的本
質請
參考
我的另一隨筆:
對
.net
事件的看法
。
一、
為
什
麼
Control
類
提供了
Invoke
和
BeginInvoke
機制?
關
於
這
個
問題
的最主要的原因已
經
是
dotnet
程序
員
眾所周知的,我在此
費
點筆墨再次
記錄
到自己
的日志,以便日後提醒一下自己。
1
、
windows
程序消息機制
Windows
GUI
程序是基於消息機制的,有個主
線
程
維護
著一個消息
泵
。
這
個消息
泵讓
windows
程序生生不息。
Windows GUI
程序的消息循
環
Windows
程序有個消息
隊
列,
窗體上的所有消息是
這
個
隊
列裡面消息的最主要來源。
這
裡的
while
循
環
使用了
GetMessage
()
這
個方法,
這
是個阻塞方法,也就是
隊
列
為
空
時
方法就會被阻塞,從
而
這
個
while
循
環
停止運
動
,
這
避免了一個程序把
cpu
無
緣
無故地耗盡,
讓
其它程序
難
以得到響
應
。當然在某些需要
cpu
最大限度運
動
的程序裡面就可以使用另外的方法,
例如某些
3d
游
戲
或者
及
時戰
略游
戲
中,一般會使用
PeekMessage
()
這
個方法,它不會被
windows
阻塞,從而保
證
整
個游
戲
的流
暢
和比
較
高的
幀
速。
這
個主
線
程
維護
著整個窗體以及上面的子控件。當它得到一個消息,就會
調
用
DispatchMessage
方法派遣消息,
這
會引起
對
窗體上的窗口
過
程的
調
用。
窗口
過
程裡面當然是程序
員
提供的窗體數據
更新代
碼
和其它代
碼
。
2
、
dotnet
裡面的消息循
環
public static void Main(string[] args)
{
Form f = new Form();
Application.Run(f);
}
Dotnet
窗體程序封裝了上述的
while
循
環
,
這
個循
環
就是通
過
Application.Run
方法啟
動
的。
3
、
線
程外操作
GUI
控件的
問題
如果從另外一個
線
程操作
windows
窗體上的控件,
就會和主
線
程
產
生
競
爭,
造成不可
預
料的
結
果,
甚至死
鎖
。
因此
windows GUI
編
程有一個
規則
,
就是只能通
過創
建控件的
線
程來操作控件的數據,
否
則
就可能
產
生不可
預
料的
結
果。
因此,
dotnet
裡面,
為
了方便地解決
這
些
問題
,
Control
類實現
了
ISynchronizeInvoke
接口,提
供了
Invoke
和
BeginInvoke
方法來提供
讓
其它
線
程更新
GUI
界面控件的機制。
public interface ISynchronizeInvoke
{
[HostProtection(SecurityAction.LinkDemand,
Synchronization=true,
ExternalThreading=true)]
IAsyncResult BeginInvoke(Delegate method, object[] args);
object EndInvoke(IAsyncResult result);
object Invoke(Delegate method, object[] args);
bool InvokeRequired { get; }
}
}
如果從
線
程外操作
windows
窗體控件,那
麼
就需要使用
Invoke
或者
BeginInvoke
方法,通
過
一
個委托把
調
用封送到控件所屬的
線
程上
執
行。
二、消息機制
---
線
程
間
和
進
程
間
通信機制
1
、
window
消息
發
送
Windows
消息機制是
windows
平台上的
線
程或者
進
程
間
通信機制之一。
Windows
消息
值
其
實
就
是定
義
的一個數據
結
構,最重要的是消息的
類
型,它就是一個整數;
然後就是消息的參數。消息的
參數可以表示很多
東
西。
Windows
提供了一些
api
用來向一個
線
程的消息
隊
列
發
送消息。因此,一個
線
程可以向另一個
線
程的消息
隊
列
發
送消息從而告
訴對
方做什
麼
,
這樣
就完成了
線
程
間
的通信。
有些
api
發
送消息需要
一個窗口句柄,
這種
函數可以把消息
發
送到指定窗口的主
線
程消息
隊
列;
而有些
則
可以直接通
過線
程句柄,把消息
發
送到
該線
程消息
隊
列中。
用消息機制通信
SendMessage
是
windows api
,用來把一個消息
發
送到一個窗口的消息
隊
列。
這
個方法是個阻塞
方法,
也就是操作系
統
會確保消息的確
發
送到目的消息
隊
列,
並且
該
消息被
處
理完
畢
以後,
該
函數
才返回。返回之前,
調
用者將會被
暫時
阻塞。
PostMessage
也是一個用來
發
送消息到窗口消息
隊
列的
api
函數,但
這
個方法是非阻塞的。也就
是它會
馬
上返回,而不管消息是否真的
發
送到目的地,也就是
調
用者不會被阻塞。
2
、
Invoke and BeginInvoke
下載
還剩5頁未讀,繼續閱讀