ManualResetEvent 未按预期工作 - 表单挂起
ManualResetEvent is not working as expected - Form is hanging
我写了一个 class,它使用 工作线程 并利用了 事件 对象。我已将 class 缩减为最基本的内容:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Threading;
using System.Windows.Forms;
namespace TEST
{
public class TEST_Worker
{
public static ManualResetEvent m_Event = new ManualResetEvent(false);
private BackgroundWorker m_backgroundWorker;
public TEST_Worker()
{
InitBackgroundWorker();
}
private void InitBackgroundWorker()
{
m_backgroundWorker = new BackgroundWorker();
m_backgroundWorker.DoWork += new DoWorkEventHandler(backgroundWorker_DoWork);
m_backgroundWorker.ProgressChanged += new ProgressChangedEventHandler(backgroundWorker_ProgressChanged);
m_backgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker_RunWorkerCompleted);
m_backgroundWorker.WorkerReportsProgress = true;
}
public void start()
{
m_Event.Reset();
m_backgroundWorker.RunWorkerAsync();
}
public void stop()
{
m_backgroundWorker.CancelAsync();
}
public void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
m_backgroundWorker.ReportProgress(100, "Progress {0}%");
}
// This event handler updates the UI
private void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
}
private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
m_Event.Set();
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
// dispose managed resources
m_backgroundWorker.Dispose();
}
// free native resources
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
}
在表单 class(菜单项处理程序)中,我正在这样做:
private void testToolStripMenuItem_Click(object sender, EventArgs e)
{
TEST.TEST_Worker myTest = new TEST.TEST_Worker();
myTest.start();
TEST.TEST_Worker.m_Event.WaitOne();
MessageBox.Show("Complete!");
}
我没听清楚。表单需要不休眠或任何东西(否则 GUI 将不会更新 - 真正的代码会更新进度条)。但是,我还希望表单知道线程何时完成,然后执行任务。目前它只是在调用 start
.
之后继续
显然我没有以正确的方式使用 ManualResetEvent
。目前我的应用程序只是无限期地挂起。它从不显示消息框(我不希望线程显示它 - 但表单)。
这有意义吗?我是不是用错了方法?
我以前用过,不过我承认是当工作线程需要等待子工作线程完成后才能继续。这个上下文是不同的,一个表单调用一个工作线程,然后在线程完成时想要做一些事情(但不会阻塞表单以进行 GUI 更新)。
如评论中所述,您可能想尝试从 class 引发自定义事件,该事件包装了 Background Worker:
public class TEST_Worker
{
public event EventHandler OnCompleted = delegate { };
// ....
private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
OnCompleted(this, EventArgs.Empty);
}
}
// In form:
private void testToolStripMenuItem_Click(object sender, EventArgs e)
{
TEST.TEST_Worker myTest = new TEST.TEST_Worker();
myTest.OnCompleted += (_sender, _e) => {
MessageBox.Show("Complete!");
};
myTest.start();
}
另一种方法是使用原始线程和同步通过 Invoke 访问表单,如下所述:Accessing a form's control from a separate thread
我写了一个 class,它使用 工作线程 并利用了 事件 对象。我已将 class 缩减为最基本的内容:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Threading;
using System.Windows.Forms;
namespace TEST
{
public class TEST_Worker
{
public static ManualResetEvent m_Event = new ManualResetEvent(false);
private BackgroundWorker m_backgroundWorker;
public TEST_Worker()
{
InitBackgroundWorker();
}
private void InitBackgroundWorker()
{
m_backgroundWorker = new BackgroundWorker();
m_backgroundWorker.DoWork += new DoWorkEventHandler(backgroundWorker_DoWork);
m_backgroundWorker.ProgressChanged += new ProgressChangedEventHandler(backgroundWorker_ProgressChanged);
m_backgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker_RunWorkerCompleted);
m_backgroundWorker.WorkerReportsProgress = true;
}
public void start()
{
m_Event.Reset();
m_backgroundWorker.RunWorkerAsync();
}
public void stop()
{
m_backgroundWorker.CancelAsync();
}
public void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
m_backgroundWorker.ReportProgress(100, "Progress {0}%");
}
// This event handler updates the UI
private void backgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
{
}
private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
m_Event.Set();
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
// dispose managed resources
m_backgroundWorker.Dispose();
}
// free native resources
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
}
}
在表单 class(菜单项处理程序)中,我正在这样做:
private void testToolStripMenuItem_Click(object sender, EventArgs e)
{
TEST.TEST_Worker myTest = new TEST.TEST_Worker();
myTest.start();
TEST.TEST_Worker.m_Event.WaitOne();
MessageBox.Show("Complete!");
}
我没听清楚。表单需要不休眠或任何东西(否则 GUI 将不会更新 - 真正的代码会更新进度条)。但是,我还希望表单知道线程何时完成,然后执行任务。目前它只是在调用 start
.
显然我没有以正确的方式使用 ManualResetEvent
。目前我的应用程序只是无限期地挂起。它从不显示消息框(我不希望线程显示它 - 但表单)。
这有意义吗?我是不是用错了方法?
我以前用过,不过我承认是当工作线程需要等待子工作线程完成后才能继续。这个上下文是不同的,一个表单调用一个工作线程,然后在线程完成时想要做一些事情(但不会阻塞表单以进行 GUI 更新)。
如评论中所述,您可能想尝试从 class 引发自定义事件,该事件包装了 Background Worker:
public class TEST_Worker
{
public event EventHandler OnCompleted = delegate { };
// ....
private void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
OnCompleted(this, EventArgs.Empty);
}
}
// In form:
private void testToolStripMenuItem_Click(object sender, EventArgs e)
{
TEST.TEST_Worker myTest = new TEST.TEST_Worker();
myTest.OnCompleted += (_sender, _e) => {
MessageBox.Show("Complete!");
};
myTest.start();
}
另一种方法是使用原始线程和同步通过 Invoke 访问表单,如下所述:Accessing a form's control from a separate thread