【问题标题】:ManualResetEvent is not working as expected - Form is hangingManualResetEvent 未按预期工作 - 表单挂起
【发布时间】:2016-05-27 18:29:31
【问题描述】:

我编写了一个使用工作线程的类,它使用了一个事件对象。我已将课程缩减为基础知识:

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);
        }
    }
}

在表单类(菜单项处理程序)中,我正在这样做:

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 更新)。

【问题讨论】:

  • 对我来说,您似乎在 BackgroundThreadWorker 上使用Async 函数 - 它与您停止消息泵的情况不符(我的意思是您正在阻止应用程序中的主线程等待 @ 987654327@).
  • @csharpfolk 有什么替代方案?如果我删除 WaitOne 调用,表单如何实现我想要实现的目标?工人完成后能否以某种方式通知父母?
  • 经过一番搜索后,问题略有不同,BackgroundWorker 将尝试在 UI 线程 stackoverflow.com/questions/2806814/… 上触发您在 WaitOne 上阻塞等待的事件
  • @csharpfolk 好的,如果我删除那个 WaitOne,我们还有其他方法可以继续吗?
  • 您可以将自定义事件添加到您的工作人员类,并在工作人员的 OnCompleted 事件上调用它。

标签: c# backgroundworker manualresetevent


【解决方案1】:

如评论中所述,您可能想尝试从包装后台工作人员的类中引发自定义事件:

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

【讨论】:

  • 没错。这里不需要ManualResetEventOnCompleted 处理程序可以满足他的需要。
  • 我在真实文件中遇到错误:CS0136 无法在此范围内声明名为“sender”的本地或参数,因为该名称在封闭的本地范围中用于定义本地或参数 GENIO查看器 D:\My Programs\GENIO Viewer\GENIO Viewer\GENIO_Viewer_Form.cs 125 活动错误 CS0136 无法在此范围内声明名为“e”的本地或参数,因为该名称在封闭的本地范围中用于定义本地或参数GENIO Viewer D:\My Programs\GENIO Viewer\GENIO Viewer\GENIO_Viewer_Form.cs 125 活动
  • 名称冲突 - 抱歉,我已经解决了
  • 谢谢!我已经能够在我的真实课堂上对其进行调整,并在线程完成后应用我想要的代码。都好。 :)
猜你喜欢
  • 2019-12-25
  • 2018-01-27
  • 1970-01-01
  • 1970-01-01
  • 2020-06-23
  • 2019-09-01
  • 2016-04-23
  • 2021-04-04
  • 1970-01-01
相关资源
最近更新 更多