C# 当我在同一个类中调用给定的方法时,线程似乎停止运行,为什么?

C# 当我在同一个类中调用给定的方法时,线程似乎停止运行,为什么?,c#,multithreading,C#,Multithreading,我有一个课程,通过USB不断刷新物理连接到PC的设备。监视方法在线程上运行,检查\u监视标志,而开始和停止方法只是设置和取消设置该标志 我当前的问题是:当线程运行时,我得到了预期的“忙”和“不忙”控制台打印,但是当我调用Stop方法时,它会一直运行,而(\u busy)永远运行,因为\u monitoringread似乎停止运行了 我怀疑它停止运行是因为最后一次打印总是忙,也就是说,ExecuteMonitoring在中途运行,然后没有人知道(至少我不知道) 暂停调试和查看StackTrace也

我有一个课程,通过USB不断刷新物理连接到PC的设备。监视方法在线程上运行,检查
\u监视
标志,而
开始
停止
方法只是设置和取消设置该标志

我当前的问题是:当线程运行时,我得到了预期的“忙”和“不忙”控制台打印,但是当我调用
Stop
方法时,它会一直运行
,而(\u busy)
永远运行,因为
\u monitoringread
似乎停止运行了

我怀疑它停止运行是因为最后一次打印总是
,也就是说,
ExecuteMonitoring
在中途运行,然后没有人知道(至少我不知道)

暂停调试和查看StackTrace也没有任何帮助,因为它永远保存在
while(\u busy)
语句中的
Stop()
方法中

public class DeviceMonitor
{
    bool _running;
    bool _monitoring;
    bool _busy = false;
    MonitoringMode _monitoringMode;
    Thread _monitoringThread;

    readonly object _lockObj = new object();


    // CONSTRUTOR
    public DeviceMonitor()
    {
        _monitoringThread = new Thread(new ThreadStart(ExecuteMonitoring));
        _monitoringThread.IsBackground = true;
        _running = true;
        _monitoringThread.Start();            
    }


    public void Start()
    {
        _monitoring = true;
    }

    public void Stop()
    {
        _monitoring = false;
        while (_busy)
        {                
            Thread.Sleep(5);
        }
    }


    void ExecuteMonitoring()
    {
        while (_running)
        {
            Console.WriteLine("ExecuteMonitoring()");

            if (_monitoring)
            {
                lock (_lockObj)
                {
                    _busy = true;
                }
                Console.WriteLine("busy");

                if (_monitoringMode == MonitoringMode.SearchDevices)
                {
                    SearchDevices();
                }
                else
                if (_monitoringMode == MonitoringMode.MonitorDeviceConnection)
                {
                    MonitorDeviceConnection();
                }

                lock (_lockObj)
                {
                    _busy = false;
                }
                Console.WriteLine("not busy");              
            }
            Thread.Sleep(1000);
            _busy = false;                
        }
    }

    private void SearchDevices()
    {
        var connected = ListDevices();

        if (connected.Count > 0)
        {
            Device = connected.First();
            ToggleMonitoringMode();
        }
        else
            Device = null;
    }


    void MonitorDeviceConnection()
    {
        if (Device == null)
        {
            ToggleMonitoringMode();
        }
        else
        {
            bool responding = Device.isConnected;
            Console.WriteLine("responding " + responding);
            if (!responding)
            {
                Device = null;
                ToggleMonitoringMode();
            }
        }

    }


    void ToggleMonitoringMode()
    {
        if (_monitoringMode == MonitoringMode.SearchDevices)
            _monitoringMode = MonitoringMode.MonitorDeviceConnection;
        else
        if (_monitoringMode == MonitoringMode.MonitorDeviceConnection)
            _monitoringMode = MonitoringMode.SearchDevices;
    }

    enum MonitoringMode
    {
        SearchDevices,
        MonitorDeviceConnection
    }
}    

最有可能的解释是:优化:编译器看到
\u busy
停止
方法中从未更改,因此允许将
\u busy
替换为
,从而将其转换为无止境循环。这是有效的,因为
\u busy
字段没有标记为易失性,因此优化器不必假设其他线程上发生了更改

因此,请尝试将
\u busy
标记为volatile。或者,更好——实际上更好——使用
ManualResetEvent

ManualResetEvent _stopMonitoring = new ManualResetEvent(false);
ManualResetEvent _monitoringStopped = new ManualResetEvent(false);
ManualResetEvent _stopRunning = new ManualResetEvent(false);

public void Stop()
{
    _stopMonitoring.Set();
    _monitoringStopped.Wait();
}

void ExecuteMonitoring()
{
    while (!_stopRunning.Wait(0))
    {
        Console.WriteLine("ExecuteMonitoring()");

        if(!_stopMonitoring.Wait(0))
        {
            _monitoringStopped.Unset();
            // ...
        }
        _monitoringStopped.Set();
        Thread.Sleep(1000);
    }
}

代码来自内存,可能包含一些打字错误。

\u busy仅在代码中出现一次,甚至没有定义。这是你的真实密码吗?还有,不要那样做。相反,请使用
ManualResetEvent
@Amit谢谢你的指点,这是我的错别字,应该到处都是
\u busy
,去纠正它。原始代码不是英文的。从哪里调用Stop()方法?虽然我同意“忙等待”是错误的,但我不同意使用
ManualResetEvent
的建议。应该使用更好的.NET本机线程同步机制。也就是说,您的主要问题似乎是为什么
\u busy
标志从未设置为
true
;根据您观察到的
\u monitoringread
实际上已终止,并且您从未看到
“not busy”
消息,因此线程可能在到达清除
\u busy
标志的语句之前抛出异常。很好,很好,很好!:)。不过,有两个想法:1)正如你已经说过的,它看起来像;2) 我已经相信你的选择会更好,只是还没有理解为什么会更好。你介意详细说明一下吗?(顺便说一句,声明
volatile bool\u busy
并不能解决问题,我会尽快尝试
ManualResetEvent
方法。)@heltonbiker:是的,因为“volatile是邪恶的”。主要是因为它是一个非常复杂的关键字,从链接的答案中可以看出。我的回答中过于简单的解释也突出了一个事实,那就是它太容易出错。但另一个原因很简单,ManualResetEvent没有像您的循环那样执行活动等待,其中包含
线程。Sleep(5)
。@heltonbiker:如果MRE也不能解决问题,那么我们就缺少了一些上下文。事实上,只有一个答案存在,这表明在您显示的代码中很可能没有其他原因。