我使用相同的代码提出了上一个问题,并建议使用ManualResetEvent
,因为这是做我想要的正确方法,我同意这一点。
问题是:我已阅读并重新阅读了有关ManualResetEvent
,WaitOne
,Set
和{{1}的Unset
的文档和大量教程方法,但坦率地说,我不太明白它们应该如何使用。
我的代码做了什么:它一直在寻找连接的设备,当它找到一个时,它会不断验证它是否仍然连接(否则,再次开始寻找)。这是“监控”活动,可以使用Reset
和Start
方法通过客户端代码启动或停止。还有一个Stop
标志,因此_busy
方法仅在一个监视周期完成后返回。
事实是:目前bool标志方法不起作用,所以我想用Stop
方法替换它,但是无法弄清楚如何开始。
ManualResetEvent
和SearchDevices()
方法是否有条件地在同一个线程中运行,或者每个方法是否应该拥有(或者是)自己的线程?MonitorDeviceConnection()
和Start
之间的差异(打开和关闭,从客户端代码调用)和两种监控方法之间的“选择”如何影响每个ManualResetEvent的使用方式? (不太确定这个问题有多大意义)Stop
上下文”中摆脱它的合理方法是什么?以下是代码:
ManualResetEvent
答案 0 :(得分:1)
ManualResetEvent
和AutoResetEvent
之间存在差异。您始终必须重置ManualResetEvents
。当你进入一个房间时,你可以把它们想象成手动门关闭和自动关门。
对于ManualResetEvent
,您必须手动调用Reset()
,否则线程将继续运行,除非您调用重置。
我尝试使用AutoResetEvent
为您的问题创建模拟器。希望这会给你更清晰的画面。如果您愿意,可以稍后尝试更改并使用ManualResetEvent
。
如果需要,这个序列继续进行切换状态。
在此示例中,我将使用2个线程一个用于搜索设备,另一个用于监控设备状态。 RulyCanceler
将是您取消的令牌。这将替换您使用的_busy
标志。
public class DeviceMonitorSignaling
{
readonly object _lockObj = new object();
EventWaitHandle searchingHandle;
EventWaitHandle monitoringHandle;
bool _running;
bool _monitoring;
volatile Device device;
MonitoringMode _monitoringMode;
Thread _monitoringThread;
Thread _searchDeviceThread;
RulyCanceler CancelToken;
// CONSTRUTOR
public DeviceMonitorSignaling()
{
CancelToken = new RulyCanceler();
searchingHandle = new AutoResetEvent(false);
monitoringHandle = new AutoResetEvent(false);
_monitoringThread = new Thread
(() =>
{
try { MonitorDeviceConnection(CancelToken); }
catch (OperationCanceledException)
{
Console.WriteLine("Canceled Search!");
}
});
_searchDeviceThread = new Thread(() =>
{
try { SearchDevices(CancelToken); }
catch (OperationCanceledException)
{
Console.WriteLine("Canceled Monitor!");
}
});
_monitoringThread.IsBackground = true;
}
public void Start()
{
_monitoring = true;
_running = true;
_searchDeviceThread.Start();
_monitoringThread.Start();
}
public void Stop()
{
CancelToken.Cancel();
// One of the thread would be sleeping to identify and recall it.
WakeSleepingThread();
}
/// <summary>
/// Method to search the device.
/// </summary>
/// <param name="cancelToken"></param>
void SearchDevices(RulyCanceler cancelToken)
{
while (_running)
{
cancelToken.ThrowIfCancellationRequested();
Console.WriteLine("Searching devices....");
Thread.Sleep(1000);
device = new Device(); // may be some logic to detect the device.
Console.WriteLine("Finished!!! Searching devices. Start monitoring.");
if(device != null)
{
// Block the search thread and start the monitoring thread.
ToggleMonitoringMode();
}
}
}
/// <summary>
/// Once the device is detected
/// </summary>
/// <param name="cancelToken"></param>
void MonitorDeviceConnection(RulyCanceler cancelToken)
{
monitoringHandle.WaitOne();
Console.WriteLine("monitoring started.");
while (_monitoring)
{
cancelToken.ThrowIfCancellationRequested();
Thread.Sleep(1000);
if (device == null)
{
Console.WriteLine("Disconnected Invoking search.");
// Block monitoring thread and awake the device search.
ToggleMonitoringMode();
}
else
{
bool responding = device.isConnected;
Console.WriteLine("responding {0}", responding);
if (!responding)
{
Console.WriteLine("Not responding. Invoking search.");
device = null;
// Block monitoring thread and awake the device search.
ToggleMonitoringMode();
}
}
}
}
internal void ToggleMonitoringMode()
{
if (_monitoringMode == MonitoringMode.SearchDevices)
{
_monitoringMode = MonitoringMode.MonitorDeviceConnection;
monitoringHandle.Set();
searchingHandle.WaitOne();
}
else if (_monitoringMode == MonitoringMode.MonitorDeviceConnection)
{
_monitoringMode = MonitoringMode.SearchDevices;
searchingHandle.Set();
monitoringHandle.WaitOne();
}
}
internal void WakeSleepingThread()
{
if(_monitoringMode == MonitoringMode.MonitorDeviceConnection)
{
searchingHandle.Set();
}
else
{
monitoringHandle.Set();
}
}
enum MonitoringMode
{
SearchDevices,
MonitorDeviceConnection
}
/// <summary>
/// For test purpose remove the device.
/// </summary>
internal void DisconnectDevice()
{
if(device != null)
{
device = null;
}
}
/// <summary>
/// For test purpose change the device status
/// </summary>
internal void ChangeDeviceState()
{
if (device != null)
{
device.Disconnect();
}
}
/// <summary>
/// Dummy device
/// </summary>
internal class Device
{
public bool isConnected = false;
public Device()
{
isConnected = true;
}
public void Disconnect()
{
isConnected = false;
}
}
internal class RulyCanceler
{
object _cancelLocker = new object();
bool _cancelRequest;
public bool IsCancellationRequested
{
get { lock (_cancelLocker) return _cancelRequest; }
}
public void Cancel() { lock (_cancelLocker) _cancelRequest = true; }
public void ThrowIfCancellationRequested()
{
if (IsCancellationRequested) throw new OperationCanceledException();
}
}
}
如果查看Stop()方法,此方法使用CancelToken发送中断信号。 WakeSleepThread
用于唤醒任何一个睡眠线程。
static void Main(string[] args)
{
var obj = new DeviceMonitorSignaling();
Console.WriteLine("Starting...");
obj.Start();
Thread.Sleep(4000); // after 4 sec remove the device.
Console.WriteLine("Changing device state.");
obj.DisconnectDevice();
Thread.Sleep(4000); // // after 4 sec change the device status.
obj.ChangeDeviceState();
Console.Read();
Console.WriteLine("Stopping...");
obj.Stop();
Console.Read();
}
我使用上面的模拟来更改设备状态,将设备对象设置为null。如果你运行该程序,你会看到类似的输出。
注意:可能有一些方面需要改进此示例代码。随意优化。