I have made a previous question with the same code, and have been advised to use ManualResetEvent
, because it is the right way of doing what I want, and I agree with that.
Problem is: I have read and re-read the docs and a lot of tutorials about ManualResetEvent
, with its WaitOne
, Set
, Unset
and Reset
methods, but frankly I didn't quite understand how they are supposed to be used.
What my code does: it keeps looking for connected devices, and when it finds one, it keeps verifying if it's still connected (otherwise, start looking for again). This is the "monitoring" activity, which can be started or stopped by client code using Start
and Stop
methods. There is also a _busy
flag, so that Stop
method only returns after one monitoring cycle is complete.
Fact is: currently the bool flag approach is not working, so I want to replace it with ManualResetEvent
approach, but cannot figure out even how to start.
- Should I replace the flags by ManualResetEvents, one-to-one?
- Should
SearchDevices()
andMonitorDeviceConnection()
methods conditionally run in the same thread, or should each one have (or be) its own thread? - How the difference between
Start
andStop
(turning on and off, called from client code) and "selecting" between both monitoring methods affect the way each ManualResetEvent is used? (not quite sure this question makes much sense) - Using an enum flag to select one of two possible paths of execution is quite a code smell, isn't it? What would be a sensible way of getting rid of it in a "
ManualResetEvent
context"?
Here's the code:
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
}
}