上次在调试串口的时候,遇到了Invoke卡死的bug,第一次接触到了BeginInvoke,于是就找了找这两者的区别。
Invoke and BeginInvoke
这篇文章介绍了windows程序消息机制,有兴趣可以看一下。
总结下来就是这么回事:
使用BeginInvoke方法封送一个委托方法,类似于使用PostMessage进行通信,这是一个异步方法。也就是该方法封送完毕后马上返回,不会等待委托方法的执行结束,调用者线程将不会被阻塞。但是调用者也可以使用EndInvoke方法或者其它类似WaitHandle机制等待异步操作的完成。
但是在内部实现上,Invoke和BeginInvoke都是用了PostMessage方法,从而避免了SendMessage带来的问题。而Invoke方法的同步阻塞是靠WaitHandle机制来完成的。
如果用代码来看的话,下面两种写法的效果是完全相同的。
this.Invoke(new Action(() =>
textBox1.AppendText(s);
}));
IAsyncResult asyncResult = this.BeginInvoke(new Action(() =>
textBox1.AppendText(s);
}));
while (!asyncResult.AsyncWaitHandle.WaitOne())
this.EndInvoke(asyncResult);
IAsyncResult asyncResult = this.BeginInvoke(new Action(() =>
textBox1.AppendText(s);
}));
while (!asyncResult.IsCompleted)
this.EndInvoke(asyncResult);
假如代理通知的事情一直没有完成,使用Invoke就会一直阻塞再这里。
考虑到asyncResult.IsCompleted不具有阻塞性,即cpu会一直执行类似while(true)的语句,程序是真的退不出去。而asyncResult.AsyncWaitHandle.WaitOne()还具有多个重载:
public virtual bool WaitOne();
public virtual bool WaitOne(int millisecondsTimeout);
参考c#线程之异步委托begininvoke、invoke、AsyncWaitHandle.WaitOne 、异步回调和BeginInvoke和EndInvoke方法两篇博客,可以使用WaitOne(int millisecondsTimeout)
方法。
如果invoke没有返回,则阻塞500ms后,WaitOne()函数返回false,可以做异常处理。
如果500ms以内返回,正常结束Invoke。
IAsyncResult asyncResult = this.BeginInvoke(new Action(() =>
textBox1.AppendText(s);
}));
if (asyncResult.AsyncWaitHandle.WaitOne(500))
this.EndInvoke(asyncResult);
MessageBox.Show("返回超时");
通过一个委托来进行同步方法的异步调用,也是.net提供的异步调用机制之一。但是Delegate.BeginInvoke方法是从ThreadPool取出一个线程来执行这个方法,以获得异步执行效果的。也就是说,如果采用这种方式提交多个异步委托,那么这些调用的顺序无法得到保证。而且由于是使用线程池里面的线程来完成任务,使用频繁,会对系统的性能造成影响。
Delegate.BeginInvoke也是讲一个委托方法封送到其它线程,从而通过异步机制执行一个方法。调用者线程则可以在完成封送以后去继续它的工作。但是这个方法封送到的最终执行线程是运行库从ThreadPool里面选取的一个线程。
这里需要纠正一个误区,那就是Control类上的异步调用BeginInvoke并没有开辟新的线程完成委托任务,而是让界面控件的所属线程完成委托任务的。看来异步操作就是开辟新线程的说法不一定准确。

实际也测试过,在Action中加Thread.Sleep,会让UI线程1s响应一次,因为这里的BeginInvoke是Control.Invoke,并不是单独开一个线程去执行的Action。
上次在调试串口的时候,遇到了Invoke卡死的bug,第一次接触到了BeginInvoke,于是就找了找这两者的区别。Invoke and BeginInvoke这篇文章介绍了windows程序消息机制,有兴趣可以看一下。总结下来就是这么回事:使用BeginInvoke方法封送一个委托方法,类似于使用PostMessage进行通信,这是一个异步方法。也就是该方法封送完毕后马上返回,不会等待...
invoke和begininvoke 区别
一直对invoke和begininvoke的使用和概念比较混乱,这两天看了些资料,对这两个的用法和原理有了些新的认识和理解。
首先说下,invoke和begininvoke的使用有两种情况:
1. control中的invoke、begininvoke。
2. delegrate中的invoke、begininvoke。
这两...
在WPF多线程编程中,经常要在工作线程中更新界面显示,Invoke和BeginInvoke即是为了解决此类问题。
在WPF多线程编程模型中,通过Dispatcher调度程序,来管理UI工作项队列,并拥有应用程序主线程,在大多数WPF应用程序中,只存在一个用户界面线程和一个调度器。
在非UI线程更新UI,通过调用Invoke和BeginInvoke来实现,那么两者有什么区别呢?
Invoke是同步更新,会阻塞所在工作者线程,BeginInvoke是异步更新,不会阻塞当前线程。
Invoke调用后
在主线程中开了一个子线程,如果要在子线程中修改主线程某个控件,会触发异常:“线程间操作无效: 从不是创建控件“button1”的线程访问它。”。
1.正确的写法是需要使用Invoke,Invoke方法需要创建一个委托。如下所示,我要修改一个Button控件的文字:
Thread testThread1=new Thread(new ThreadStart(process1));//主函数中创建一个子线程
testThread1.IsBackground = true;
testThread1.Start()
C#中的Invoke和BeginInvoke都是用来在UI线程上执行委托的方法。
Invoke方法会阻塞当前线程,直到委托执行完成。而BeginInvoke方法则是异步执行委托,不会阻塞当前线程。
使用Invoke方法时,如果当前线程是UI线程,则委托会直接在UI线程上执行。如果当前线程不是UI线程,则Invoke方法会将委托加入UI线程的消息队列中,等待UI线程空闲时执行。
使用BeginInvoke方法时,委托会被异步执行,不会阻塞当前线程。当委托执行完成后,会通过回调函数通知调用线程。
总之,Invoke和BeginInvoke都是用来在UI线程上执行委托的方法,只是在执行方式和阻塞方式上有所不同。
### 回答2:
很抱歉,但是您没有给出关于问题的上下文或内容,因此无法提供有针对性的回答。请提供更多信息或问题的详细描述,以便我可以为您提供更好的帮助。感谢您的理解与配合!
### 回答3:
很抱歉,您的问题不够具体明确,无法给出有意义的回答。如果您可以提供更多的信息或明确您的问题,我们将很乐意为您提供帮助和回答。谢谢!
C# 异常:已引发: "线程间操作无效: 从不是创建控件“textBox1”的线程访问它。" (System.InvalidOperationException)
there for u:
C#根据字符串获取成员变量的值
CubeMX 5.5 修改HAL库库函数版本
NBplusnm:
CubeMX 5.5 修改HAL库库函数版本
小菠萝_YAN: