【问题标题】:Thread synchronization in C# using Monitor Wait/Pulse在 C# 中使用 Monitor Wait/Pulse 进行线程同步
【发布时间】:2011-08-19 00:24:07
【问题描述】:

我正在处理一个 C# 中的多线程项目,但我控制工作线程的想法并不像我希望的那样容易。

主 GUI 窗口启动时会创建一个线程,这是它正在运行的函数:

    private void continueReading()
    {
        while (true)
        {
            lock (_lock)
            {
                while (!startDAQ)
                    Monitor.Wait(_lock);
                startDAQ = false;
                logging = true;

                daqTaskComponent1.ReadAsync();
            }
        }

    }

现在,当在 GUI 上单击按钮时,startDAQ 设置为 true,并且 _lock 被脉冲以启动调用 ReadAsync() 的线程。

在 Async 的回调函数中,我锁定同一个 _lock 对象并执行一些计算,然后将 startDAQ 设置为 true 并再次脉冲。

这允许我的 Async 函数仅在回调准备好处理更多数据时被调用,这就是它需要的方式。

问题是我需要能够安全地暂停数据收集,方法是让 continueReading 线程在 Monitor.Wait 上暂停,如果在暂停前调用了 ReadAsync,则允许回调完成。

这是当用户再次单击按钮暂停数据收集时我正在运行的代码:

    lock (_lock)
    {
        startDAQ = false;
        Monitor.PulseAll(_lock);
        while (logging)
            Monitor.Wait(_lock);
    }

这不能正常工作,我遇到了一些死锁。这是我第一次使用 Monitor 和 Wait/Pulsing 在线程之间发出信号,所以我有点难过,感觉有一种更简单的方法来处理这个问题。感谢您提供任何帮助或建议。

编辑:以下是回调函数的相关代码:

    lock (_lock)
    {
        //Lots of code here that just manipulates the data passed to the callback
        startDAQ = true;
        logging = false;
        Monitor.PulseAll(_lock);
    }

添加了我最初粘贴代码时忘记的日志记录布尔值。

【问题讨论】:

  • 请解释您的问题是什么。试图获得一个可能是错误的解决方法可能会让人头疼。
  • 问题是我的当前代码出现了死锁。我不确定如何使运行循环的线程安全地暂停。我希望用户能够单击一个按钮来启动和停止调用 ReadAsync 的线程。当用户停止线程时,我必须执行一些清理,这会导致回调函数出现问题,这就是为什么我需要在清理发生之前完成任何挂起的 ReadAsync。
  • startDAQ 必须声明为 volatile
  • 我尝试将 startDAQ 和日志记录都声明为 volatile,但似乎没有任何帮助。我已经看到当用户再次单击按钮时它试图锁定时卡住了,并且我看到它在到达 while(logging) 后卡在该锁内的 Monitor.Wait() 上。

标签: c#


【解决方案1】:

你为什么不简单地从 GUI 线程调用ReadAsync(因为它已经是异步的),然后从完成回调中再次调用它。不需要其他(显式)线程或同步。

【讨论】:

  • 我想我从来没有真正理解在哪个上下文回调中执行。他们在新线程中吗?只是看不到我将如何中断调用过程,以便用户可以暂停数据收集。
  • 回调将在线程池线程的上下文中。要中断,请发出完成回调信号以不再调用ReadAsync。我建议您使用ManualResetEvent 进行此操作。在回调中,等待超时为 0 的事件。如果等待失败,请不要再次调用ReadAsync
  • 我尝试了您的建议,开始时效果很好,但我仍然遇到停止问题。我的按钮的事件处理程序在异步回调完成并导致一些空引用错误之前完成并清理对象。我尝试设置另一个仅在回调完成时设置的事件,但我猜事件处理程序和回调在同一个线程上执行,因为一旦我将事件处理程序设置为等待回调,它就会死锁。
猜你喜欢
  • 2021-10-11
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-05-06
  • 2018-03-10
  • 2011-11-03
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多