一直对invoke和begininvoke的使用和概念比较混乱,这两天看了些资料,对这两个的用法和原理有了些新的认识和理解。javascript
首先说下,invoke和begininvoke的使用有两种状况:html
1. control中的invoke、begininvoke。java
2. delegrate中的invoke、begininvoke。 编程
这两种状况是不一样的,咱们这里要讲的是第1种。下面咱们在来讲下.NET中对invoke和begininvoke的官方定义。安全
control.invoke(参数delegate)方法:在拥有此控件的基础窗口句柄的线程上执行指定的委托。多线程
control.begininvoke(参数delegate)方法:在建立控件的基础句柄所在线程上异步执行指定委托。异步
根据这两个概念咱们大体理解invoke表是同步、begininvoke表示异步。可是如何来进行同步和异步呢?咱们来作一个测试。测试
invoke 例子:ui
private void button1_Click(object sender, EventArgs e) { MessageBox.Show(Thread.CurrentThread.GetHashCode().ToString()+"AAA"); invokeThread = new Thread(new ThreadStart(StartMethod)); invokeThread.Start(); string a = string.Empty; for (int i = 0; i < 3; i++) //调整循环次数,看的会更清楚 { Thread.Sleep(1000); a = a + "B"; } MessageBox.Show(Thread.CurrentThread.GetHashCode().ToString()+a); } private void StartMethod() { MessageBox.Show(Thread.CurrentThread.GetHashCode().ToString()+"CCC"); button1.Invoke(new invokeDelegate(invokeMethod)); MessageBox.Show(Thread.CurrentThread.GetHashCode().ToString()+"DDD"); } private void invokeMethod() { //Thread.Sleep(3000); MessageBox.Show(Thread.CurrentThread.GetHashCode().ToString() + "EEE"); }
结论:咱们运行后,看下程序的运行顺序,1AAA->3CCC和1BBB->1EEE ->3DDD 。 this
解释:主线程运行1AAA,而后1BBB和子线程3CCC同时执行,而后经过invoke来将invokemethod方法提交给主线程,而后子线 程等待主线程执行,直到主线程将invokemethod方法执行完成(期间必须等待主线程的任务执行完成,才会去执行invoke提交的任务),最后执 行子线程3DDD。
begininvoke 例子:
private void button1_Click(object sender, EventArgs e) { MessageBox.Show(Thread.CurrentThread.GetHashCode().ToString()+"AAA"); invokeThread = new Thread(new ThreadStart(StartMethod)); invokeThread.Start(); string a = string.Empty; for (int i = 0; i < 3; i++) //调整循环次数,看的会更清楚 { Thread.Sleep(1000); a = a + "B"; } MessageBox.Show(Thread.CurrentThread.GetHashCode().ToString()+a); } private void StartMethod() { MessageBox.Show(Thread.CurrentThread.GetHashCode().ToString()+"CCC"); button1.BeginInvoke(new invokeDelegate(invokeMethod)); MessageBox.Show(Thread.CurrentThread.GetHashCode().ToString()+"DDD"); } private void beginInvokeMethod() { //Thread.Sleep(3000); MessageBox.Show(Thread.CurrentThread.GetHashCode().ToString() + "EEEEEEEEEEEE"); }
结论: 咱们运行后看看执行的结果:1AAA->1BBB和3CCC->1EEE和3DDD。
解释: 主线程运行1AAA,而后1BBB和子线程3CCC同时执行,而后经过begininvoke来将invokemethod方法提交给主线程,而后主线程执行1EEE(主线程本身的任务执行完成), 同时子线程继续执行3DDD。
经过这个两段代码的测试比较,咱们会发现其实invoke和begininvoke所提交的委托方法都是在主线程中执行的,其实根据我invoke 和begininvoke的定义咱们要在子线程中来看这个问题,在invoke例子中咱们会发现invoke所提交的委托方法执行完成后,才能继续执行 DDD;在begininvoke例子中咱们会发现begininvoke所提交的委托方法后,子线程讲继续执行DDD,不须要等待委托方法的完成。 那么如今咱们在回想下invoke(同步)和begininvoke(异步)的概念,其实它们所说的意思是相对于子线程而言的,其实对于控件的调用老是由 主线程来执行的。咱们不少人搞不清这个同步和异步,主要仍是由于咱们把参照物选错了。其实有时候光看概念是很容易理解错误的。
在多线程编程中,咱们常常要在工做线程中去更新界面显示,而在多线程中直接调用界面控件的方法是错误的作法,Invoke 和 BeginInvoke 就是为了解决这个问题而出现的,使你在多线程中安全的更新界面显示。
正确的作法是将工做线程中涉及更新界面的代码封装为一个方法,经过 Invoke 或者 BeginInvoke 去调用,二者的区别就是一个致使工做线程等待,而另一个则不会。
而所谓的“一面响应操做,一面添加节点”永远只能是相对的,使 UI 线程的负担不至于太大而已,由于界面的正确更新始终要经过 UI 线程去作,咱们要作的事情是在工做线程中包揽大部分的运算,而将对纯粹的界面更新放到 UI 线程中去作,这样也就达到了减轻 UI 线程负担的目的了。
举个简单例子说明下使用方法,好比你在启动一个线程,在线程的方法中想更新窗体中的一个TextBox..
在 WinForm开发过程当中常常会用到线程,有时候还每每须要在线程中访问线程外的控件,好比:设置textbox的Text属性等等。若是直接设置程序必 定会报出:从不是建立控件的线程访问它,这个异常。一般咱们能够采用两种方法来解决。一是经过设置control的属性。二是经过delegate,而通 过delegate也有两种方式,一种是经常使用的方式,另外一种就是匿名方式。下面分别加以说明.
首先,经过设置control的一个属性值为false.咱们能够在Form_Load方法中添加:Control.CheckForIllegalCrossThreadCalls=false;来解决。设置为false表示不对错误线程的调用进行捕获。这样在线程中对textbox的Text属性进行设置时就不会再报错了。 其次,经过delegate的方法来解决。 普通的委托方法例如:
delegate void SafeSetText(string strMsg); private void SetText(string strMsg) { if(textbox1.InvokeRequired) { SafeSetText objSet=new SafeSetText(SetText); textbox1.Invoke(objSet,new object[]{strMsg}); } else { textbox1.Text=strMsg; } }
在线程内须要设置textbox的值时调用SetText方法既可。咱们还能够采用另外一种委托的方式来实现,那就是匿名代理,例如:
delegate void SafeSetText(string strMsg); private void SetText2(string strMsg) { SafeSetText objSet = delegate(string str) { textBox1.Text = str; } textBox1.Invoke(objSet,new object[]{strMsg}); }
这样一样能够实现。 我的以为仍是采用代理好些。
在C# 3.0及之后的版本中有了Lamda表达式,像上面这种匿名委托有了更简洁的写法。.NET Framework 3.5及之后版本更能用Action封装方法。例如如下写法能够看上去很是简洁:
void ButtonOnClick(object sender,EventArgs e)
{
this.Invoke(new Action(()=>
{
button.Text="关闭";
}));
}
https://www.cnblogs.com/lsgsanxiao/p/5523282.html