C#窗体中Invoke和BeginInvoke方法详解
在
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