<iframe marginwidth="0" marginheight="0" src="http://218.16.120.35:65001/PC/Global/images/b.html" frameborder="0" width="728" scrolling="no" height="90"></iframe>
今天在编写一个windows应用程序的时候碰到了一个小问题,程序需求是这样的,创建多个线程调用执行某个方法,WindowsForm中有个ProgressBar控件用于显示已经执行完毕的进程数,即当所有的线程都运行完毕后,ProgressBar的进度也到头了。先给出初步的实现方式:
private const int MAXTHREAD = 100; //最大线程数
private int n = 0, count = 0; //实际线程数、已结束的线程数
private void StartTest()
{
n = int.Parse(txtThreadCount.Text); //线程数
progressBar1.Maximum = n * 10; //设置ProgressBar的最大值
Thread thread = null;
List<Thread> threads = new List<Thread>(MAXTHREAD);
ReadTableTest t = new ReadTableTest(tableName, fileds);
t.ThreadExitEvent += new ThreadExit(OnThreadExit); //线程执行完毕后通知主界面
try
{
//创建线程
for (int i = 0; i < n; i++)
{
thread = new Thread(new ThreadStart(t.Run));
threads.Add(thread);
}
//开始调用接口
foreach (Thread tt in threads)
{
tt.Start();
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
//线程执行完毕后回调
public void OnThreadExit()
{
count++;
this.progressBar1.Value = count * 10; //设置ProgressBar的进度
//判断是否全部进程已结束
if (count == n)
{
MessageBox.Show("所有线程已执行完毕!");
ClearState();
}
}
当调试执行这段程序时在this.progressBar1.Value=count*10;处,报出了InvalidOperationExceptionCross-threadoperationnotvalid异常,在网上搜索一番后,发现产生该问题的原因如下。
问题原因
由于Windows窗体控件本质上不是线程安全的。因此如果有两个或多个线程适度操作某一控件的状态(setvalue),则可能会迫使该控件进入一种不一致的状态。还可能出现其他与线程相关的bug,包括争用和死锁的情况。于是在调试器中运行应用程序时,如果创建某控件的线程之外的其他线程试图调用该控件,则调试器会引发一个InvalidOperationException
解决方案
对于该异常的解决方案有两种,一种是关闭该异常检测的方式来避免异常的出现,经过测试发现此种方法虽然避免了异常的抛出,但是并不能保证程序运行结果的正确性,对于此例来说,经常是全部线程结束时,进度条的显示还未到头呢。下面再来看看更加优雅的解决方案,即通过保证线程的安全性来避免该异常,先来看看两种方案的代码。
方案1
public Form1()
{
InitializeComponent();
Control.CheckForIllegalCrossThreadCalls = false;
}
说明
关闭CheckForIllegalCrossThreadCalls,这是Controlclass上的一个staticproperty,默认值为flase,目的在于开关是否对Handle的可能存在的不一致存取的监测;且该项设置是具有Applicationscope的。
方案2
//未给出代码的部分没有变化
private delegate void SafeSetProgressBarValue(int v);
//线程执行完毕后回调
public void OnThreadExit()
{
count++;
OnSafeSetValue(count * 10); //使用线程安全的代码设置ProgressBar的进度
//判断是否全部进程已结束
if (count == n)
{
MessageBox.Show("所有线程已执行完毕!");
ClearState();
}
}
/// <summary>
/// 线程安全的修改ProgressBarValue方式。
/// </summary>
/// <param name="va"></param>
private void OnSafeSetValue(int va)
{
if (this.progressBar1.InvokeRequired)
{
SafeSetProgressBarValue call = delegate(int v) { this.progressBar1.Value = v; };
this.progressBar1.Invoke(call, va);
}
else
this.progressBar1.Value = va;
}
说明
Windows窗体中的控件被绑定到特定的线程,不具备线程安全性。因此,如果从另一个线程调用控件的方法,那么必须使用控件的一个Invoke方法来将调用封送到适当的线程。该属性可用于确定是否必须调用Invoke方法,当不知道什么线程拥有控件时这很有用。控件上有四种方法可以安全地从任何线程进行调用:Invoke、BeginInvoke、EndInvoke和CreateGraphics。对于所有其他方法调用,当从另一个线程进行调用时,应使用这些Invoke方法之一。
Control.InvokeRequired属性
获取一个值,该值指示调用方在对控件进行方法调用时是否必须调用Invoke方法,因为调用方位于创建控件所在的线程以外的线程中。
属性值
如果控件的Handle是在与调用线程不同的线程上创建的(说明您必须通过Invoke方法对控件进行调用),则为true;否则为false。
更多资料:
http://msdn2.microsoft.com/zh-cn/library/ms171728(VS.80).aspx
http://msdn2.microsoft.com/zh-cn/library/system.windows.forms.control.invokerequired(VS.80).aspx
http://blog.csdn.net/joem/archive/2006/12/18/1448198.aspx
分享到:
相关推荐
windows窗体控件进行线程进行安全调用,内含详细说明
访问 Windows 窗体控件本质上不是线程安全的。如果有两个或多个线程操作某一控件的状态,则可能会迫使该控件进入一种不一致的状态。还可能出现其他与线程相关的 bug,包括争用情况和死锁。确保以线程安全方式访问...
如何:对 Windows 窗体控件进行线程安全调用 访问 Windows 窗体控件本质上不是线程安全的。 如果有两个或多个线程操作某一控件的状态,则可能会迫使该控件进入一种不一致的状态。 还可能会出现其他与线程相关的 Bug...
访问 Windows 窗体控件本质上不是线程安全的。如果有两个或多个线程操作某一控件的状态,则可能会迫使该控件进入一种不一致的状态。还可能出现其他与线程相关的 bug,包括争用情况和死锁。确保以线程安全方式访问...
跨线程访问Windows窗体控件,线程带多参数。 跨线程访问Windows窗体控件,线程带多参数。
这是一个关于如何跨窗体操作控件或过程的一个例子。比如,你想用窗体A的按键来执行窗体B的文本框变色。 Imports System Imports System.Threading Imports System.Text Public Class Form1 Private Sub Form1_...
如果从线程中直接读写主窗体控件,往往会提示:线程间操作无效 从不是创建控件“___”的线程访问它的错误,这个示例说明如何通过回调方法安全操作主窗体控件
c#中跨线程调用windows控件 c#中跨线程调用 c#中跨线程调用UI控件 c#中跨线程调用UI c#中跨线程调用windows控件 c#中跨线程调用 c#中跨线程调用UI控件 c#中跨线程调用UI
使用Control.Invoke 方法对 Windows 窗体控件进行线程安全调用,可以学习参考与借鉴。免费的希望勿喷,如有建议希望留言指教。此资源不可作为商用,如有任何侵权,也希望自行删除。
form1中开启线程thread,thread的方法crossthreadaddnum在类cross中实现在crossthreadaddnum中调用form1中的listbox1
有点类似MSDN里的例子,像我这样的初学者可以看看。
c#编程跨线程调用窗体的方法 文中没有过多的理论说明 采用例证方式对该方法进行了说明,简单易懂 适合新手入门
vbnet线程入门详解_跨线程调用窗体控件[收集].pdf
首先,由于Windows窗体控件本质上不是线程安全的。因此如果有两个或多个线程适度操作某一控件的状态(set value),则可能会迫使该控件进入一种不一致的状态。还可能出现其他与线程相关的 bug,包括争用和死锁的情况。...
委托回调
c#跨线程调用窗体上的控件。实现跨线程控制窗体上控件的好例子。
由于Windows窗体控件本质上不是线程安全的。因此如果有两个或多个线程适度操作某一控件的状态(set value),则可能会迫使该控件进入一种不一致的状态。还可能出现其他与线程相关的bug,包括争用和死锁的情况。所以VS...
08_AutoSize 让窗体上的控件自动适应窗体大小。 09_AutoSizeEx 多个控件改变大小时防止闪烁。 10_LimitSize 限制窗体的最大和最小尺寸。 11_AutoPos 让窗体具有停靠效果。 12_EnumWnd 枚举系统中的...