How to use ManualResetEvent to replace boolean flags in this class - c#

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() and MonitorDeviceConnection() methods conditionally run in the same thread, or should each one have (or be) its own thread?
How the difference between Start and Stop (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
}
}

There's a difference in ManualResetEvent and AutoResetEvent. You always have to reset the ManualResetEvents. you can imagine them like Manual door closing and Auto door closing when you enter in a room.
For ManualResetEvent you have to manually call the Reset() other wise the thread would keep on running unless you call the Reset.
I have tried to create a simulator for your problem using the AutoResetEvent. Hope this will give you more clear picture. Later if you want you can try changing and using ManualResetEvent as you may.
If you look at the Idea of this implementation then it works like this:
And this sequence goes on for switching states if necessary.
In this sample I'll be using 2 threads one for search device and other for Monitoring the device status. The RulyCanceler will be your token for cancellation. This would be the replacement of _busy flag that you have used.
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();
}
}
}
If you look at the Stop() method this method is using the CancelToken to send an interrup signal. WakeSleepThread is used to wake the any of the sleeping thread out of two.
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();
}
I have used above simultion to change the device status and device object to set as null. If you run the program you'll see the output something like this.
Note: There might be areas to improve this sample code. Feel free to optimize as you may.
References - http://www.albahari.com/threading/

Related

Process.WaitForExit hangs even without using RedirectStandardError/RedirectStandardOutput

We have a service which starts a process and waits for process to exit when service is stopped/ user of service calls stop (to stop/kill process started by service).
Sporadically, process.waitForExit(TimeSpan) hangs.
Please note that process started by Service is native process (C++/CLI) process and service is in C#.
Following is the code snippet we are using
public class ApplicationProcessControl : IProcessControl
{
private Process _proc;
private const int ProcessIdleTimeout = 5000;
public bool Start(string arguments)
{
if (IsAlive)
{
Log.TraceInfo("Application process already running. Killing it now...");
_proc.Kill();
}
var eProcStarted = new Mutex(false, "Mutex111");
_proc = new Process { EnableRaisingEvents = true, StartInfo = new ProcessStartInfo(_exePath, arguments) { RedirectStandardOutput = false,RedirectStandardError = false};
_proc.Exited += OnProcessExited;
_proc.Start();
bool started;
if(_proc == null)
{
Log.TraceInfo("Unable to start application process");
started = false;
}
else
{
started = eProcStarted.WaitOne(ProcessIdleTimeout);
if(started)
{
Log.TraceInfo($"Application process with id {_proc.Id} started successfully");
}
}
eProcStarted.Dispose();
return started;
}
public void Kill()
{
_proc.Kill();
}
public bool WaitForProcessToExit(TimeSpan timeout)
{
return _proc.WaitForExit((int) timeout.TotalMilliseconds);
}
public event Action ProcessExited;
private void OnProcessExited(object sender, EventArgs e)
{
var proc = sender as Process;
if(proc != null)
{
proc.Exited -= OnProcessExited;
if(proc.ExitCode == 0)
{
Log.TraceInfo("Application process exited gracefully");
}
else
{
Log.DeveloperWarning("Application process exited unexpectedly with code {0}", proc.ExitCode);
OnProcessExited();
}
}
}
private void OnProcessExited()
{
Action handler = ProcessExited;
handler?.Invoke();
}
}
public interface IProcessControl
{
bool IsAlive { get; }
bool Start(string arguments);
bool WaitForProcessToExit(TimeSpan timeout);
void Kill();
event Action ProcessExited;
}
public class ApplicationClientService: DisposableObject, IComponentService, ITaskControl, IUIControl,
IDataProvider<AngleFlavors>, IApplicationCloseNotifier
{
//...
private readonly IProcessControl _procCtrl;
public ApplicationClientService(IObjectProvider objPro)
{
//...
_procCtrl.ProcessExited += OnApplicationProcessExited;
}
public void Stop()
{
//...
CleanUpAppProcess();
//...
}
private void CleanUpAppProcess()
{
//...
if(!_procCtrl.WaitForProcessToExit(TimeSpan.FromSeconds(5)))
{
_procCtrl.Kill();
}
}
private void OnApplicationProcessExited()
{
if(!_isAppRunning)
{
return;
}
_isAppRunning = false;
_autoLaunchRequested = false;
RaiseApplicationClosed();
Log.DeveloperWarning("Application process closed unexpectedly");
Log.UserMessageApplicationClosedUnexpectedly();
...
}
protected virtual void RaiseApplicationClosed()
{
//AuditApplicationStop();
//ApplicationClosed?.Invoke();
}
}
Don't know if this can answer your question (I have myself more questions than answers on this), but this code:
private void CleanUpAppProcess()
{
//...
if(!_procCtrl.WaitForProcessToExit(TimeSpan.FromSeconds(5)))
{
_procCtrl.Kill();
}
}
calls WaitForExit before the Kill command. Are you expecting the process to terminate by itself / to be terminated by a user in between 5 seconds? As Bennie Zhitomirsky pointed out in his comment, the mutex is not owned when it should be (if I understood correctly what you want to achieve, if not, sorry). What about the implementation of IsAlive?
Anyway, I put down some lines for the ApplicationProcessControl class. I just tested it a bit with some native process and seems to work (but still, I'm not sure this is what you're trying to achive):
public class ApplicationProcessControl : IProcessControl
{
/// <summary>
/// Process instance variable.
/// </summary>
private Process _proc;
/// <summary>
/// The thread will try to acquire the mutex for a maximum of _mutexAcquireTimeout ms.
/// </summary>
private const int _mutexAcquireTimeout = 5000;
/// <summary>
/// Global static named mutex, seen by all threads.
/// </summary>
private static Mutex SpawnProcessMutex = new Mutex(false, "Mutex111");
/// <summary>
/// The state of the process.
/// </summary>
public bool IsAlive
{
get { return !(_proc is null) && !_proc.HasExited; }
}
/// <summary>
/// Spawns a new process.
/// </summary>
public bool Start(string arguments)
{
// Try to acquire the mutex for _mutexAcquireTimeout ms.
if (!SpawnProcessMutex.WaitOne(_mutexAcquireTimeout) || IsAlive)
{
// Mutex is still owned (another thread got it and is trying to run the process)
// OR the process is already running.
// DO NOT start a new process.
return false;
}
try
{
// Mutex is acquired by this thread.
// Create a new instance of the Process class.
_proc = new Process
{
EnableRaisingEvents = true,
StartInfo = new ProcessStartInfo("the_process_to_be_run", arguments)
{
RedirectStandardOutput = false,
RedirectStandardError = false
}
};
// Subscription to the ProcessExited event.
_proc.Exited += OnProcessExited;
// Run the process.
var haveAnHandle = _proc.Start();
// *******
// TODO: The process started but we may not have an handle to it. What to do?
// *******
//Log.TraceInfo($"Application process with id {_proc.Id} started successfully");
return true;
}
catch (Exception) // TODO: [Catch the specific exceptions here]
{
// The process failed to start, still we have an instance of Process with no use.
if (!(_proc is null))
{
_proc.Dispose();
_proc = null;
}
//Log.TraceInfo("Unable to start application process");
return false;
}
finally
{
// Release the mutex, another thread may be waiting to acquire it.
SpawnProcessMutex.ReleaseMutex();
}
}
/// <summary>
/// Kills the process started by the Start method.
/// </summary>
public void Kill()
{
if (IsAlive) _proc.Kill();
}
/// <summary>
/// Can't see a real reason to block the thread waiting synchronously for the process to
/// exit, we are already subscribed to the Exited event.
/// Kept here to avoid breaking the interface contract.
/// </summary>
public bool WaitForProcessToExit(TimeSpan timeout)
{
return _proc.WaitForExit((int)timeout.TotalMilliseconds);
}
/// <summary>
/// Client class consumable event to know the the process actually terminated.
/// </summary>
public event Action ProcessExited;
/// <summary>
/// Process Exited event handler.
/// </summary>
private void OnProcessExited(object sender, EventArgs e)
{
// Get a reference to the actual Process object.
var proc = sender as Process;
if (proc is null) return;
proc.Exited -= OnProcessExited;
if (proc.ExitCode == 0)
{
// Log.TraceInfo("Application process exited gracefully");
}
else
{
// Log.DeveloperWarning("Application process exited unexpectedly with code {0}", proc.ExitCode);
ProcessExited?.Invoke();
}
}
}

Thread seems to stop running when I call a given method in the same class, why?

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.
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!
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).
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
}
}
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.
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.

What is the alternative for BackgroundWorker in Windows 8.1 Universal Apps?

I am migrating my Windows Phone App to Windows Universal Apps. In Phone App, I used BackgroundWorker for database retrieval and then show in UI. Below is the class which I prepared in Windows Phone 8 and how it was called.
public class TestBackgroundWorker
{
private BackgroundWorker backgroundWorker;
ProgressIndicator progressIndicator;
public delegate void functionToRunInBackground();
public functionToRunInBackground currentFunctionToExecute;
public delegate void callbackFunction();
public callbackFunction functionToSendResult;
private bool isCancellationSupported;
private string message;
/// <summary>
///
/// </summary>
/// <param name="functionNameToExecute">specifies function name to be executed in background</param>
/// <param name="isCancellable">Flag which specifies whether the operation is cancellable or not</param>
/// <param name="functionNameWhichGetsResult">Specifies call back function to be executed after the completion of operation</param>
public MCSBackgroundWorker(functionToRunInBackground functionNameToExecute, bool isCancellable, string messageToDisplay, callbackFunction functionNameWhichGetsResult)
{
currentFunctionToExecute = functionNameToExecute;
functionToSendResult = functionNameWhichGetsResult;
isCancellationSupported = isCancellable;
message = messageToDisplay;
backgroundWorker = new BackgroundWorker();
backgroundWorker.WorkerSupportsCancellation = isCancellable;
backgroundWorker.DoWork += backgroundWorker_DoWork;
backgroundWorker.RunWorkerCompleted += backgroundWorker_RunWorkerCompleted;
}
void backgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
deactivateProgressIndicator();
functionToSendResult();
}
void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
if (currentFunctionToExecute != null)
{
currentFunctionToExecute();
}
}
public void cancelBackgroundOperation()
{
if (isCancellationSupported == true)
{
backgroundWorker.CancelAsync();
}
}
public void Start()
{
backgroundWorker.RunWorkerAsync();
activateProgressIndicator();
}
void activateProgressIndicator()
{
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
var currentPage = App.RootFrame.Content as PhoneApplicationPage;
SystemTray.SetIsVisible(currentPage, true);
SystemTray.SetOpacity(currentPage, 0.5);
SystemTray.SetBackgroundColor(currentPage, Colors.White);
SystemTray.SetForegroundColor(currentPage, Colors.Black);
progressIndicator = new ProgressIndicator();
progressIndicator.IsVisible = true;
progressIndicator.IsIndeterminate = true;
progressIndicator.Text = message;
SystemTray.SetProgressIndicator(currentPage, progressIndicator);
});
}
void deactivateProgressIndicator()
{
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
if (progressIndicator != null)
{
var currentPage = App.RootFrame.Content as PhoneApplicationPage;
progressIndicator.IsVisible = false;
SystemTray.SetIsVisible(currentPage, false);
}
});
}
public bool isBackgroundWorkerBusy()
{
return backgroundWorker != null ? backgroundWorker.IsBusy : false;
}
}
}
And calling that as below to run the process in background.
private void loadReports()
{
bgWorker = new TestBackgroundWorker(loadReportsFromDB, true, "Loading...", showReports);
bgWorker.Start();
}
Here, loadReprtsFromDB and showReports are two functions.
Questions:
Can anyone suggest how to achieve same thing in Windows 8.1?
Is there any alternative for PhoneApplicationService.Current.State?
IMHO, even for the desktop, the Task<T> and Progress<T> classes offer a nice alternative to BackgroundWorker, and they are both supported on Windows Phone 8.1. The Task<T> class provides the mechanism to start and then cleanly wait for background operations, while the Progress<T> class provides the mechanism for reporting progress (not part of your example or question, but I mention it because that's the one thing Task along with async/await doesn't provide from BackgroundWorker).
Your example could be changed to something like this:
public class TestBackgroundWorker
{
private Task _task;
private CancellationTokenSource _cancelSource;
public CancellationToken CancellationToken
{
get { return _cancelSource != null ? _cancelSource.Token : null; }
}
ProgressIndicator progressIndicator;
public readonly Action<TestBackgroundWorker> currentFunctionToExecute;
private string message;
/// <summary>
///
/// </summary>
/// <param name="functionNameToExecute">specifies function name to be executed in background</param>
/// <param name="isCancellable">Flag which specifies whether the operation is cancellable or not</param>
/// <param name="functionNameWhichGetsResult">Specifies call back function to be executed after the completion of operation</param>
public MCSBackgroundWorker(Action<TestBackgroundWorker> functionNameToExecute, bool isCancellable, string messageToDisplay)
{
currentFunctionToExecute = functionNameToExecute;
_cancelSource = isCancellable ? new CancellationTokenSource() : null;
message = messageToDisplay;
}
public void cancelBackgroundOperation()
{
if (_cancelSource != null)
{
_cancelSource.Cancel();
}
}
public async Task Start()
{
activateProgressIndicator();
_task = Task.Run(() => currentFunctionToExecute(this));
await _task;
_task = null;
deactivateProgressIndicator();
}
void activateProgressIndicator()
{
// In theory, you should not need to use Dispatcher here with async/await.
// But without a complete code example, it's impossible for me to
// say for sure, so I've left it as-is.
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
var currentPage = App.RootFrame.Content as PhoneApplicationPage;
SystemTray.SetIsVisible(currentPage, true);
SystemTray.SetOpacity(currentPage, 0.5);
SystemTray.SetBackgroundColor(currentPage, Colors.White);
SystemTray.SetForegroundColor(currentPage, Colors.Black);
progressIndicator = new ProgressIndicator();
progressIndicator.IsVisible = true;
progressIndicator.IsIndeterminate = true;
progressIndicator.Text = message;
SystemTray.SetProgressIndicator(currentPage, progressIndicator);
});
}
void deactivateProgressIndicator()
{
// Likewise.
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
if (progressIndicator != null)
{
var currentPage = App.RootFrame.Content as PhoneApplicationPage;
progressIndicator.IsVisible = false;
SystemTray.SetIsVisible(currentPage, false);
}
});
}
public bool isBackgroundWorkerBusy()
{
return _task != null;
}
}
Then you could use it something like this:
private async Task loadReports()
{
bgWorker = new TestBackgroundWorker(loadReportsFromDB, true, "Loading...");
await bgWorker.Start();
showReports();
}
void loadReportsFromDB(TaskBackgroundWorker worker)
{
while (...)
{
if (worker.CancellationToken.IsCancellationRequested)
{
return; // or whatever
}
}
}
To deal with cancellation, the functionNameToExecute delegate would need to be for a method that accepts an instance of TaskBackgroundWorker as a parameter, so that it can retrieve the CancellationToken property value to check for cancellation (similar to the DoWork() event handler…though your code example didn't actually suggest any mechanism by which the actual background operation code would even detect cancellation).
Note that with async/await, your task can also return a value if you like, via the Task<T> type instead of Task. The above example could easily be modified to accommodate that, and that feature of async/await is one of the biggest reasons I prefer it over BackgroundWorker (which has no clean, compiler-supported mechanism for returning results from the background operation).
Caveat: Lacking a complete code example to start with, there is no point for me to try to actually compile and test any of the code. So the above is strictly "browser-authored". It should suffice for the purposes of illustration, but I apologize in advance for any typos that might exist.

Monitor doesn't seem to lock the object

I'm trying to implement a basic Future class (yeah, I know about Task but this is for educational purposes) and ran into strange behavior of Monitor class. The class is implemented so that it enters the lock in constructor, queues an action which exits the lock to a thread pool. Result getter checks an instance variable to see if the action is completed and if it isn't, enters lock and then returns the result. Problem is that in fact result getter doesn't wait for the queued action to finish and proceeds anyway leading to incorrect results. Here's the code.
// The class itself
public class Future<T>
{
private readonly Func<T> _f;
private volatile bool _complete = false;
private T _result;
private Exception _error = new Exception("WTF");
private volatile bool _success = false;
private readonly ConcurrentStack<Action<T>> _callbacks = new ConcurrentStack<Action<T>>();
private readonly ConcurrentStack<Action<Exception>> _errbacks = new ConcurrentStack<Action<Exception>>();
private readonly object _lock = new object();
public Future(Func<T> f)
{
_f = f;
Monitor.Enter(_lock);
ThreadPool.QueueUserWorkItem(Run);
}
public void OnSuccess(Action<T> a)
{
_callbacks.Push(a);
if (_complete && _success)
a(_result);
}
public void OnError(Action<Exception> a)
{
_errbacks.Push(a);
if (_complete && !_success)
a(_error);
}
private void Run(object state)
{
try {
_result = _f();
_success = true;
_complete = true;
foreach (var cb in _callbacks) {
cb(_result);
}
} catch (Exception e) {
_error = e;
_complete = true;
foreach (var cb in _errbacks) {
cb(e);
}
} finally {
Monitor.Exit(_lock);
}
}
public T Result {
get {
if (!_complete) {
Monitor.Enter(_lock);
}
if (_success) {
return _result;
} else {
Console.WriteLine("Throwing error complete={0} success={1}", _complete, _success);
throw _error;
}
}
}
// Failing test
public void TestResultSuccess() {
var f = new Future<int>(() => 1);
var x = f.Result;
Assert.AreEqual (1, x);
}
I'm using Mono 3.2.3 on Mac OS X 10.9.
Only the thread that took the lock can exit the lock. You can't Enter it in the constructor on the calling thread then Exit from the thread-pool when it completes - the thread-pool worker does not have the lock.
And conversely: presumably it is the same thread that created the future that is accessing the getter: that is allowed to Enter again: it is re-entrant. Also, you need to Exit the same number of times that you Enter, otherwise it isn't actually released.
Basically, I don't think Monitor is the right approach here.

Automatically terminating non essential threads in C#

I have an object in C# on which I need to execute a method on a regular basis. I would like this method to be executed only when other people are using my object, as soon as people stop using my object I would like this background operation to stop.
So here is a simple example is this (which is broken):
class Fish
{
public Fish()
{
Thread t = new Thread(new ThreadStart(BackgroundWork));
t.IsBackground = true;
t.Start();
}
public void BackgroundWork()
{
while(true)
{
this.Swim();
Thread.Sleep(1000);
}
}
public void Swim()
{
Console.WriteLine("The fish is Swimming");
}
}
The problem is that if I new a Fish object anywhere, it never gets garbage collected, cause there is a background thread referencing it. Here is an illustrated version of broken code.
public void DoStuff()
{
Fish f = new Fish();
}
// after existing from this method my Fish object keeps on swimming.
I know that the Fish object should be disposable and I should clean up the thread on dispose, but I have no control over my callers and can not ensure dispose is called.
How do I work around this problem and ensure the background threads are automatically disposed even if Dispose is not called explicitly?
Here is my proposed solution to this problem:
class Fish : IDisposable
{
class Swimmer
{
Thread t;
WeakReference fishRef;
public ManualResetEvent terminate = new ManualResetEvent(false);
public Swimmer(Fish3 fish)
{
this.fishRef = new WeakReference(fish);
t = new Thread(new ThreadStart(BackgroundWork));
t.IsBackground = true;
t.Start();
}
public void BackgroundWork()
{
bool done = false;
while(!done)
{
done = Swim();
if (!done)
{
done = terminate.WaitOne(1000, false);
}
}
}
// this is pulled out into a helper method to ensure
// the Fish object is referenced for the minimal amount of time
private bool Swim()
{
bool done;
Fish fish = Fish;
if (fish != null)
{
fish.Swim();
done = false;
}
else
{
done = true;
}
return done;
}
public Fish Fish
{
get { return fishRef.Target as Fish3; }
}
}
Swimmer swimmer;
public Fish()
{
swimmer = new Swimmer(this);
}
public void Swim()
{
Console.WriteLine("The third fish is Swimming");
}
volatile bool disposed = false;
public void Dispose()
{
if (!disposed)
{
swimmer.terminate.Set();
disposed = true;
GC.SuppressFinalize(this);
}
}
~Fish()
{
if(!disposed)
{
Dispose();
}
}
}
I think the IDisposable solution is the correct one.
If the users of your class don't follow the guidelines for using classes that implement IDisposable it's their fault - and you can make sure that the documentation explicitly mentions how the class should be used.
Another, much messier, option would be a "KeepAlive" DateTime field that each method called by your client would update. The worker thread then checks the field periodically and exits if it hasn't been updated for a certain amount of time. When a method is setting the field the thread will be restarted if it has exited.
This is how I would do it:
class Fish3 : IDisposable
{
Thread t;
private ManualResetEvent terminate = new ManualResetEvent(false);
private volatile int disposed = 0;
public Fish3()
{
t = new Thread(new ThreadStart(BackgroundWork));
t.IsBackground = true;
t.Start();
}
public void BackgroundWork()
{
while(!terminate.WaitOne(1000, false))
{
Swim();
}
}
public void Swim()
{
Console.WriteLine("The third fish is Swimming");
}
public void Dispose()
{
if(Interlocked.Exchange(ref disposed, 1) == 0)
{
terminate.Set();
t.Join();
GC.SuppressFinalize(this);
}
}
~Fish3()
{
if(Interlocked.Exchange(ref disposed, 1) == 0)
{
Dispose();
}
}
}

Categories