最近在学多线程方面的知识,看了很多东西跟很多例子,有点感悟,写下来吧:
声明:本文中的一些字句跟例子是引用横竖都溢
http://www.cnblogs.com/smartls/archive/2011/04/08/2008981.html#2104297这里的;
现将关于利用Control.Invoke与Control.BeginInvoke对比解决窗体假死问题进行详细解说:
首先看的时候你需要有以下知识:
如果你的后台线程在更新一个UI控件的状态后不需要等待,而是要继续往下处理,那么你就应该使用BeginInvoke来进行异步处理。如果你的后台线程需要操作UI控件,并且需要等到该操作执行完毕才能继续执行,那么你就应该使用Invoke。否则,在后台线程和主截面线程共享某些状态数据的情况下,如果不同步调用,而是各自继续执行的话,可能会造成执行序列上的问题,虽然不发生死锁,但是会出现不可预料的显示结果或者数据处理错误。
1、Control.Invoke,Control.BeginInvoke和delegate.Invoke,delegate.BeginInvoke是不同的。
2、Control.Invoke中的委托方法,执行在主线程,也就是我们的UI线程。而Control.BeginInvoke从命名上来看虽然具有异步调用的特征(Begin),但也仍然执行在UI线程。
3、如果在UI线程中直接调用Invoke和BeginInvoke,数据量偏大时,依然会造成UI的假死。
例子:
![2011040809094074.jpg](https://i-blog.csdnimg.cn/blog_migrate/c79095ff8cb290e37b414c7c1853499d.jpeg)
private void button1_Click( object sender, EventArgs e)
{
new Thread((ThreadStart)( delegate ()
{
for ( int i = 0 ; i < Max_Item_Count; i ++ )
{
// 此处警惕值类型装箱造成的"性能陷阱"
listView1.Invoke((MethodInvoker) delegate ()
{
listView1.Items.Add( new ListViewItem( new string []
{ i.ToString(), string .Format( " This is No.{0} item " , i.ToString()) }));
});
};
}))
.Start();
}
![2011040809115985.jpg](https://i-blog.csdnimg.cn/blog_migrate/2cc7f9eb5ebc3e8f22e2d59de87dda18.jpeg)
于是你可以在它界面上比划(点击,拉滚动条...)都没事,因为这时的工作主线程刚好可以做它,因为他是空的
至于begininvoke是由于它不等待操作ui完毕而是立即返回执行了工作线程,这样造成主线程跟工作线程同时在执行
没有主线程来理会你的比划(点击,拉滚动条...),所以你比划多了自然就卡死了。甚至
当工作线程跟主线程共享某些状态数据的情况下,工作线程的执行时间比主线程快时,将会造成执行序列上的问题,虽然不发生死锁,
但是会出现不可预料的显示结果或者数据处理错误。
如果在主线程中加载大数据(很慢),那么即使用了invoke你比划也会卡住的。
invoker.BeginInvoke(null, null);
private void Sleep()
{
for (int i = 0; i < count; i++)
{
listView1.Invoke((MethodInvoker)delegate()
{
listView1.Items.Add(new ListViewItem(new string[] { i.ToString(), string.Format("This is No.{0} item", i.ToString()) }));
});
}
}