C# 跨线程交互
有人可以帮助我如何在我的类中设置 Thread.join() 方法,或者是否有一种巧妙的方法来处理 SynchronizationContext
类和 thread.join
方法。基本上,我试图从不同的线程(不是 UI 线程)每 2 秒更新一次 datagridview (dgv) 单元格和进度条 (pb)。当一个线程完成这项工作时,该功能可以正常工作;但是,我想设置 2 个线程,以便第一个线程(线程 1)将更新控件(在我的例子中,它将更新 datagridview 并显示 10 行,进度条将更新到 50%)。一旦线程 1 完成其工作,线程 2 就应该启动并更新控件(在我的例子中,它将更新 datagridview 并显示另外 10 行,进度条将更新到 100%)。请参阅下面的代码。
using System;
using System.Diagnostics;
using System.Threading;
using System.Windows.Forms;
namespace DelegatesAndCallback
{
public partial class Form1 : Form
{
private Thread newThread1;
private Thread newThread2;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
int id = Thread.CurrentThread.ManagedThreadId;
Trace.WriteLine("Button thread "+id);
SynchronizationContext uiContext = SynchronizationContext.Current;
// thread #1
startThread1(uiContext);
// thread #2
startThread2(uiContext);
}
public void startThread1(SynchronizationContext sc)
{
// thread #1
newThread1 = new Thread(Process1) { Name = "Thread 1" };
newThread1.Start(sc);
//newThread1.Join();
}
public void startThread2(SynchronizationContext sc)
{
// thread #2
newThread2 = new Thread(Process2) { Name = "Thread 2" };
newThread2.Start(sc);
//newThread2.Join();
}
public void updateProgressBarValue(object state)
{
double val = Convert.ToDouble(state)/19.0;
pb.Value = (int)(100*val);
}
public void updateDataGridViewValue(object state)
{
dgv.Rows.Add((int) state, (int) state);
}
public void Process1(object state)
{
SynchronizationContext uiContext = state as SynchronizationContext;
for (int i = 0; i < 10; i++)
{
uiContext.Send(updateDataGridViewValue, i);
uiContext.Send(updateProgressBarValue, i);
Thread.Sleep(2000);
}
}
public void Process2(object state)
{
SynchronizationContext uiContext = state as SynchronizationContext;
for (int i = 10; i < 20; i++)
{
if (uiContext != null) uiContext.Send(updateProgressBarValue, i);
if (uiContext != null) uiContext.Send(updateDataGridViewValue, i);
Thread.Sleep(2000);
}
}
}
}
can someone help me how to set Thread.join() method within my class or if there is a neat way how to deal with SynchronizationContext
class and thread.join
method. basically, im trying to update a datagridview (dgv) cell and progress bar (pb) every 2 seconds from a different thread (not UI thread). the functionality works fine when one thread does the job; however, i would like to set 2 threads so that the first thread (Thread 1) will update the controls (in my case, it will update the datagridview and display 10 rows and the progress bar will be update to 50%). as soon as thread 1 has done its job, Thread 2 should start and update the controls (in my case, it will update the datagridview and display 10 more rows and the progress bar will be update to 100%). Please see code below.
using System;
using System.Diagnostics;
using System.Threading;
using System.Windows.Forms;
namespace DelegatesAndCallback
{
public partial class Form1 : Form
{
private Thread newThread1;
private Thread newThread2;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
int id = Thread.CurrentThread.ManagedThreadId;
Trace.WriteLine("Button thread "+id);
SynchronizationContext uiContext = SynchronizationContext.Current;
// thread #1
startThread1(uiContext);
// thread #2
startThread2(uiContext);
}
public void startThread1(SynchronizationContext sc)
{
// thread #1
newThread1 = new Thread(Process1) { Name = "Thread 1" };
newThread1.Start(sc);
//newThread1.Join();
}
public void startThread2(SynchronizationContext sc)
{
// thread #2
newThread2 = new Thread(Process2) { Name = "Thread 2" };
newThread2.Start(sc);
//newThread2.Join();
}
public void updateProgressBarValue(object state)
{
double val = Convert.ToDouble(state)/19.0;
pb.Value = (int)(100*val);
}
public void updateDataGridViewValue(object state)
{
dgv.Rows.Add((int) state, (int) state);
}
public void Process1(object state)
{
SynchronizationContext uiContext = state as SynchronizationContext;
for (int i = 0; i < 10; i++)
{
uiContext.Send(updateDataGridViewValue, i);
uiContext.Send(updateProgressBarValue, i);
Thread.Sleep(2000);
}
}
public void Process2(object state)
{
SynchronizationContext uiContext = state as SynchronizationContext;
for (int i = 10; i < 20; i++)
{
if (uiContext != null) uiContext.Send(updateProgressBarValue, i);
if (uiContext != null) uiContext.Send(updateDataGridViewValue, i);
Thread.Sleep(2000);
}
}
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
请参阅 Control.Invoke(),它专门设计用于让非UI 线程与进度条等交互。在这种情况下,使用 Invoke 将取代您的同步上下文以及对其
Send()
方法的使用。稍微相关的说明:创建线程的更简单的方法是:
更新
如果您需要从不同的类更新进度条,我可能会这样做:
ThreadOwner 类:
要点是线程需要对表单实例的引用,该实例公开一个更新进度条的方法。然后该方法确保更新发生在正确的线程中。
See Control.Invoke(), which is specifically designed to let non-UI threads interact with things like progress bars. In this case, use of Invoke would replace your synchronization context and your use of its
Send()
method.On a slightly related note: a far easier way to create a thread is:
Update
If you need to update the progress bar from a different class, I might do something like this:
And the ThreadOwner class:
The gist is that the thread needs a reference to your form instance, which exposes a method to update the progress bar. That method then makes sure that the update happens in the correct thread.
要同步线程,您应该使用[Manual|Auto]ResetEvents。
您应该使用其他模式来编写安全的代码。
请调查我的代码:
代码已更新以从不同的类调用 UI 更新
To syncronize threads you should use [Manual|Auto]ResetEvents.
You should use other patterns to write a safe code.
Investigate my code please:
Code was updated to call UI update from the different classes