DotNet 学习笔记
一、非UI线程(UI线程大部分为主线程)操作GUI控件的问题
如果从非UI线程操作windows窗体上的控件,就会和主线程产生竞争,造成死锁等现象。因此windows GUI编程有一个规则,就是只能通过创建控件的线程(UI线程)来操作控件的数据,否则就可能产生不可预料的结果。
因此,在dotnet里面Control类实现了ISynchronizeInvoke接口,提供了Invoke和BeginInvoke方法来提供让其它线程更新GUI界面控件的机制。
ISynchronizeInvoke 定义如下:
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; }
}
如果从非UI线程操作windows窗体控件,那么就需要使用Invoke或者BeginInvoke方法,通过一个委托把调用封送到控件所属的线程上执行,具体操作如下:
I、首先定义一个委托,当然直接使用该事件的委托也是可以的,如:
public delegate void UpdateClientListCallback();
II、 然后就是判断InvokeRequired 属性的值来决定是否要调用Invoke函数:
【InvokeRequired 属性:如果有两个线程,Thread A和Thread B,并且有一个Control c,是在Thread A里面new的。 那么在Thread A里面运行的任何方法调用c.InvokeRequired都会返回false。 相反,如果在Thread B里面运行的任何方法调用c.InvokeRequired都会返回true。 】
if (InvokeRequired)
{
//listBoxClientList 为Windows.Forms.ListBox 控件
listBoxClientList.BeginInvoke(new UpdateClientListCallback(UpdateClientList), null);
或者
UpdateClientListCallback deleListCallb= new InvokeCallback(UpdateClientList);
listBoxClientList.BeginInvoke(deleListCallb, null); //Invoke为同步,方法类似
}
else
{
UpdateClientList();
}
其中UpdateClientList()为具体方法。上面的BeginInvoke为异步调用,当非UI线程处理到此处是不需要等待处理完成(和UI线程异步处理),直接执行其他的内容。Invoke则需要非UI线程等UI线程处理完UpdateClientList()方法,再去执行其他的内容。
多线程之间数据和变量共享的方法:
1、private ArrayList m_workerSocketList = ArrayList.Synchronized(ArrayList()) //类似的可以用于其他乏类型。
2、静态变量
二、事件代理(EventHandler) 和委托(delegate)
http://langfangwangbin.blog.163.com/blog/static/100543634200982946189/