当我在同一个类中调用给定方法时,线程似乎停止运行,为什么? [英] Thread seems to stop running when I call a given method in the same class, why?

查看:39
本文介绍了当我在同一个类中调用给定方法时,线程似乎停止运行,为什么?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个类,它不断刷新通过 USB 物理连接到 PC 的设备.监控方法在检查 _monitoring 标志的线程上运行,而 StartStop 方法只是设置和取消设置该标志.

I have a class that constantly refreshes devices physically connected to PC via USB. The monitoring method runs on a thread checking a _monitoring flag, and Start and Stop methods just set and unset that flag.

我当前的问题是:当线程运行时,我得到预期的忙"和不忙"控制台打印,但是当我调用 Stop 方法时,它继续运行 而(_busy) 永远,因为不知何故_monitoringThread 似乎停止运行!

My current problem is: when the thread is running, I get the expected "busy" and "not busy" console prints, but when I call Stop method, it keeps running while(_busy) forever, because somehow the _monitoringThread seems to stop running!

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

I suspect it stops running because the last print is always busy, that is, the ExecuteMonitoring runs midway and then nobody knows (at least I don't).

暂停调试并查看 StackTrace 也无济于事,因为它永远保留在 Stop() 方法内的 while(_busy) 语句中.

Pause debugging and looking at StackTrace didn't help either, because it keeps in the while(_busy) statement inside Stop() method, forever.

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

推荐答案

最可能的解释是:优化:编译器看到 _busyStop 中永远不会改变方法,因此允许通过将 _busy 替换为 true 将其转换为无限循环.这是有效的,因为 _busy 字段没有标记为易失性,因此优化器不必假设另一个线程上发生的更改.

The most likely explanation is: optimization: The compiler sees that _busy is never changed inside the Stop method and it is therefore allowed to convert this to an endless loop by replacing _busy with true. This is valid, because the _busy field is not marked as being volatile and as such the optimizer doesn't have to assume changes happening on another thread.

因此,尝试将 _busy 标记为 volatile.或者,甚至更好 - 实际上更好 - 使用 ManualResetEvent:

So, try marking _busy as volatile. Or, even better - actually A LOT BETTER - use a 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);
    }
}

代码来自记忆,可能包含一些拼写错误.

Code is from memory, might contain some typos.

这篇关于当我在同一个类中调用给定方法时,线程似乎停止运行,为什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆