C# 当我在同一个类中调用给定的方法时,线程似乎停止运行,为什么?
我有一个课程,通过USB不断刷新物理连接到PC的设备。监视方法在线程上运行,检查C# 当我在同一个类中调用给定的方法时,线程似乎停止运行,为什么?,c#,multithreading,C#,Multithreading,我有一个课程,通过USB不断刷新物理连接到PC的设备。监视方法在线程上运行,检查\u监视标志,而开始和停止方法只是设置和取消设置该标志 我当前的问题是:当线程运行时,我得到了预期的“忙”和“不忙”控制台打印,但是当我调用Stop方法时,它会一直运行,而(\u busy)永远运行,因为\u monitoringread似乎停止运行了 我怀疑它停止运行是因为最后一次打印总是忙,也就是说,ExecuteMonitoring在中途运行,然后没有人知道(至少我不知道) 暂停调试和查看StackTrace也
\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也不能解决问题,那么我们就缺少了一些上下文。事实上,只有一个答案存在,这表明在您显示的代码中很可能没有其他原因。