These codes generates us this error:
这些代码会生成这个错误:
Cross-thread operation not valid: Control 'progressBar2' accessed from a thread other than the thread it was created on.
跨线程操作无效:控制'progressBar2'从其创建的线程以外的线程访问。
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Threading;
namespace ThreadingTest1
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
ThreadStart ts1;
ThreadStart ts2;
Thread t1;
Thread t2;
private void btnStart_Click(object sender, EventArgs e)
{
ts1 = new ThreadStart(z1);
ts2 = new ThreadStart(z2);
t1 = new Thread(ts1);
t2 = new Thread(ts2);
t1.Start();
t2.Start();
btnStart.Enabled = false;
}
public void z1()
{
for (int i = 1; i < 60; ++i)
{
progressBar1.Value += 1;
for (int j = 1; j < 10000000; ++j)
{
j += 1;
}
}
}
public void z2()
{
for (int k = 1; k < 100; ++k)
{
progressBar2.Value += 1;
for (int j = 1; j < 25000000; ++j)
{
j += 1;
}
}
}
private void btnstop_Click(object sender, EventArgs e)
{
t1.Suspend();
t2.Suspend();
}
private void btnContinue_Click(object sender, EventArgs e)
{
t1.Resume();
t2.Resume();
}
private void btnClose_Click(object sender, EventArgs e)
{
if (t1.IsAlive)
{
MessageBox.Show("Çalışan threadler var program sonlanamaz.");
}
else
{
this.Close();
}
}
}
}
3 个解决方案
#1
You can't access a UI control in a thread other than the UI thread responsible for that control.
您无法访问负责该控件的UI线程以外的线程中的UI控件。
See the WinForms page in my threading tutorial and also search for tutorials on BackgroundWorker
, a component introduced in .NET 2.0 which makes life much easier (particularly for progress bars).
请参阅我的线程教程中的WinForms页面,并在BackgroundWorker上搜索教程,后者是.NET 2.0中引入的一个组件,它使生活更加轻松(特别是对于进度条)。
Additionally, I'd try to avoid using Thread.Suspend
/Resume
, preferring a more co-operative approach (e.g. with Monitor.Wait
/Pulse
). That allows you to avoid suspending a thread while it holds a lock, etc.
另外,我试图避免使用Thread.Suspend / Resume,更喜欢更合作的方法(例如使用Monitor.Wait / Pulse)。这样可以避免在持有锁的情况下挂起线程等。
#2
For both z1 and z2 do this: Add a zSafe() Call zSafe() within z() after InvokeRequired check.
对于z1和z2,执行以下操作:在InvokeRequired检查后,在z()内添加zSafe()调用zSafe()。
public void z1Safe()
{
for (int i = 1; i < 60; ++i)
{
progressBar1.Value += 1;
for (int j = 1; j < 10000000; ++j)
{
j += 1;
}
}
}
public void z1()
{
if (this.InvokeRequired)
{
this.Invoke((MethodInvoker)delegate { z1Safe(); });
}
else
z1Safe();
}
I just implemented a similar solution in my windows form for asyn del call and it works fine.
我刚刚在我的Windows窗体中为asyn del调用实现了一个类似的解决方案,它工作正常。
#3
Cross thread exceptions are very common when you are working on a multithread application and it happens when you try to invoke a member of a control in a thread other than its own thread.To avoid that you can check InvokeRequired property of that control and invoke a delegate in its own thread or use a BackgroundWorker to run a process in background (another thread) and handle its events,When you handle BackgroundWorker events ,event handler methods will run on the main thread so there's no need to invoke a delegate.
当您处理多线程应用程序时,跨线程异常非常常见,当您尝试在除其自己的线程之外的线程中调用控件的成员时,它会发生。为了避免这种情况,您可以检查该控件的InvokeRequired属性并调用委托自己的线程或使用BackgroundWorker在后台运行进程(另一个线程)并处理其事件,当您处理BackgroundWorker事件时,事件处理程序方法将在主线程上运行,因此不需要调用委托。
Here you can find some information about BackgroundWorker
在这里,您可以找到有关BackgroundWorker的一些信息
#1
You can't access a UI control in a thread other than the UI thread responsible for that control.
您无法访问负责该控件的UI线程以外的线程中的UI控件。
See the WinForms page in my threading tutorial and also search for tutorials on BackgroundWorker
, a component introduced in .NET 2.0 which makes life much easier (particularly for progress bars).
请参阅我的线程教程中的WinForms页面,并在BackgroundWorker上搜索教程,后者是.NET 2.0中引入的一个组件,它使生活更加轻松(特别是对于进度条)。
Additionally, I'd try to avoid using Thread.Suspend
/Resume
, preferring a more co-operative approach (e.g. with Monitor.Wait
/Pulse
). That allows you to avoid suspending a thread while it holds a lock, etc.
另外,我试图避免使用Thread.Suspend / Resume,更喜欢更合作的方法(例如使用Monitor.Wait / Pulse)。这样可以避免在持有锁的情况下挂起线程等。
#2
For both z1 and z2 do this: Add a zSafe() Call zSafe() within z() after InvokeRequired check.
对于z1和z2,执行以下操作:在InvokeRequired检查后,在z()内添加zSafe()调用zSafe()。
public void z1Safe()
{
for (int i = 1; i < 60; ++i)
{
progressBar1.Value += 1;
for (int j = 1; j < 10000000; ++j)
{
j += 1;
}
}
}
public void z1()
{
if (this.InvokeRequired)
{
this.Invoke((MethodInvoker)delegate { z1Safe(); });
}
else
z1Safe();
}
I just implemented a similar solution in my windows form for asyn del call and it works fine.
我刚刚在我的Windows窗体中为asyn del调用实现了一个类似的解决方案,它工作正常。
#3
Cross thread exceptions are very common when you are working on a multithread application and it happens when you try to invoke a member of a control in a thread other than its own thread.To avoid that you can check InvokeRequired property of that control and invoke a delegate in its own thread or use a BackgroundWorker to run a process in background (another thread) and handle its events,When you handle BackgroundWorker events ,event handler methods will run on the main thread so there's no need to invoke a delegate.
当您处理多线程应用程序时,跨线程异常非常常见,当您尝试在除其自己的线程之外的线程中调用控件的成员时,它会发生。为了避免这种情况,您可以检查该控件的InvokeRequired属性并调用委托自己的线程或使用BackgroundWorker在后台运行进程(另一个线程)并处理其事件,当您处理BackgroundWorker事件时,事件处理程序方法将在主线程上运行,因此不需要调用委托。
Here you can find some information about BackgroundWorker
在这里,您可以找到有关BackgroundWorker的一些信息