侦听后台线程中的事件

本文关键字:事件 线程 后台 | 更新日期: 2023-09-27 18:33:31

我想启动一个线程来侦听事件并在后台处理它们。这是我到目前为止所做的:

private Thread mThread;
private bool mKeepHandlingIt;
private void Init()
{
    mKeepHandlingIt = true;
    mThread = new Thread(ProcessEvents);
    mThread.SetApartmentState(ApartmentState.STA);
    mThread.Start();
}
private void ProcessEvents()
{
    StaticClass.CoolEvent += HandleIt;
    StaticClass.StartDoingStuff();
    while (mKeepHandlingIt)
    {
        Application.DoEvents();
    }
    StaticClass.StopDoingStuff();
    StaticClass.CoolEvent -= HandleIt;
}
private void HandleIt(object sender, EventArgs e)
{
    //Handles it
}
protected override void Dispose()
{
    if (mThread != null)
    {
        mKeepHandlingIt = false;
        mThread.Join();
    }
}

有没有更好的方法?就像更适合此目的的线程类一样?在这种情况下,背景工作者似乎不是一个更好的选择......

但是,如果这是一个好方法,那么我有一个我不太理解的问题。上述解决方案适用于侦听事件和处理它们,但是当调用 Dispose 并且 mKeepHandlingIt 设置为 false 时,while 循环退出(如果我在循环中放置断点,调试器不会中断(,但在执行循环后没有代码并且 mThread.Join 永远不会返回。基本上。。。我想知道的是:如何停止线程,然后确保在清理之前不继续?

侦听后台线程中的事件

这段代码有很多问题。 首先,它遭受了事件处理程序在该工作线程上运行的错觉。 这不是事件的工作方式,处理程序在与触发事件的代码完全相同的线程上运行。 .NET 中没有允许它跳转到另一个线程的机制。

可以通过调试器的"调试 + 窗口 + 线程"窗口看到的内容。 在 Init(( 方法上设置一个断点,在事件处理程序上设置一个断点。 当它们中断时,切换到该调试器屏幕并记下所选的线程。

使用 Application.DoEvents(( 是非常危险的。 但不是在这里,线程没有创建任何窗口,所以没有事件要做。 相反,线程只会燃烧 100% 的核心,根本不完成任何事情。

mKeepHandlingIt 变量通常不会做您希望它做的事情。 当您在 32 位计算机上运行代码的发布版本时,线程将永远不会看到它被设置为 false,因此线程永远不会退出。 Thread.Join(( 将死锁。 这是由抖动优化器引起的,它将布尔变量存储在 CPU 寄存器中,并且永远不会从内存中重新加载它。 必须声明变量 volatile 才能防止进行此优化。 这是一个技巧,您应该始终使用适当的同步对象来发出线程信号,此处适合使用自动重置事件。

只需删除此代码,它对您没有帮助。

在大多数情况下,你不应该使用doevents。

例如,请参阅:

  • 是-做-邪恶
  • 使用应用程序事件

如果没有更多的线程可用,使用新线程创建线程可能会遇到麻烦。因此,您可以使用线程池。

但我会重新评论一下任务和 TPL

然后你可以从

Task.Factory.StartNew()

当使用异步库并且您具有诸如 continuewith 之类的函数时,有等待

另请参阅 MSDN 等待一个或多个任务

            // Wait for all tasks to complete.
            Task[] tasks = new Task[10];
            for (int i = 0; i < 10; i++)
            {
                tasks[i] = Task.Factory.StartNew(() => DoSomeWork(10000000));
            }
            Task.WaitAll(tasks);

Async 和 await 也不一定使用线程,但为此异步工作,请参阅:async-await-vs-threads

这对安全资源来说是一个很大的好处。特别是当你有io操作时。

更复杂的方法是使用某种服务总线在单独的进程中实现侦听(您想要实现的目标(