多线程编程中,常在工作线程中去更新界面显示,在多线程中直接调用界面控件的方法是错误的做法,因为不能跨线程调用控件(VS默认不允许),所以Invoke和BeginInvoke就解决了这个问题,是多线程中安全的更新界面显示。
虽然VS默认不允许跨线程调用控件,但是可以手动关闭此项检查:在窗体加载的时候将对控件的检查给置为false 即:Control.CheckForIllegalCrossThreadCalls = false;;
在多线程编程时,将工作线程中涉及更新界面的代码封装为一个方法,通过invoke或者BeginInvoke去调用,两个的区别就是一个导致工作线程等待,而另一个则不会。
“一面响应操作,一面添加节点”只是相对的,使UI线程的负担不至于太大,因为界面的正确更新始终要通过UI线程去做,我们要做的就是在工作线程中包揽大部分的运算,将对纯粹的界面更新放到UI线程中,这样
减轻UI线程的负担。
/*Invoke与BeginInvoke方法的区别:
*
* Invoke:在拥有此控件的基础窗口句柄的线程上执行指定的委托 同步
* BeginInvoke:在创建控件的基础窗口句柄所在的线程上 异步执行 指定的委托
*
* Invoke和BeginInvoke所提交的委托方法都是在主线程上执行的。
* Invoke会将提交的委托方法执行完后,才继续往下执行
* BeginInvoke则将提交完委托方法后,子线程继续执行,不会一直等待委托方法的完成
*/
一般使用多线程时都会考虑同步执行还是异步执行,并且用到委托
同步执行:在主线程执行时,主线程调用一个其他方法,此时主线程阻塞,等待调用的方法执行完成后主线程才能继续执行。
异步执行:在主线程执行时,打开一个子线程,主线程继续执行,当主线程需要子线程运行的结果时,主线程直接调用子线程运行的结果,如果在调用的时候
子线程还没有执行完成,主线程等待,直到子线程执行完成,主线程再继续执行。
异步回调:主线程执行时,打开一个子线程,主线程与子线程同步执行,主线程需要子线程运行的结果则调用其结果
委托:实际上就是将封装的方法当做一个参数传递给线程
/*示例
*1、工作线程:窗体加载
*2、子线程:界面text控件完成更新,即给text控件赋值
*运行逻辑:
*主线程开始工作,开启子线程,实例化委托,Invoke提交委托方法执行,然后主线程继续执行
*
*/
private delegate void a(); //定义 一个委托
private a b; //声明委托
Thread thread; //线程
private void Form_Load(object sender, EventArgs e)
{
b = new a(d); //实例化委托
thread = new Thread(c); //实例化线程
thread.Start(); //开启子线程,调用回调函数
}
///回调函数
private void c()
{
textBox1.Invoke(b); //子线程同步执行
}
private void b()
{
textBox1.Text = "123";
}