patterncsharpMinor
Polling loop to run in a background thread
Viewed 0 times
backgroundpollingloopthreadrun
Problem
I came up with the idea of a small utility class that will poll some delegate until the response received meets some condition, upon which it will notify the main thread which can take the appropriate action.
This is the first time I've ever done something like this, and I know that in general, polling is a bad idea, so I want to do this in a way that consumes minimal resources, and is really easy to use.
```
using System;
using System.Threading;
using System.Windows.Threading;
namespace WPF.Utilities.Common
{
/// This class allows a user to easily set up a seperate thread to poll some state,
/// and set up an event that will fire if the state meets some condition.
/// The type of the value returned by the polling delegate.
public class ConditionMonitor
{
#region Private Properties
protected bool Halted = false;
protected Dispatcher originThread = null;
protected Thread monitorThread = null;
#endregion
#region Delegates
/// A delegate provided by the user of this class which returns the current state,
/// to be tested against a certain condition in the IsConditionMet delegate.
public delegate T RequestState();
public RequestState RequestStateDelegate { get; set; }
/// A delegate provided by the user of this class which determines whether given the
/// current state, the polling program should execute the ConditionMet delegate.
public delegate bool IsConditionMet(T state);
public IsConditionMet IsConditionMetDelegate { get; set; }
/// A delegate used to handle ConditionMonitor events.
public delegate void ConditionMonitorHandler(ConditionMonitor source, T state);
/// An event which fires each time the state is polled (use sparingly).
public event ConditionMonitorHandler RequestReceived;
/// An event which fires when the condition is met.
public event ConditionMonitorHandler ConditionM
This is the first time I've ever done something like this, and I know that in general, polling is a bad idea, so I want to do this in a way that consumes minimal resources, and is really easy to use.
```
using System;
using System.Threading;
using System.Windows.Threading;
namespace WPF.Utilities.Common
{
/// This class allows a user to easily set up a seperate thread to poll some state,
/// and set up an event that will fire if the state meets some condition.
/// The type of the value returned by the polling delegate.
public class ConditionMonitor
{
#region Private Properties
protected bool Halted = false;
protected Dispatcher originThread = null;
protected Thread monitorThread = null;
#endregion
#region Delegates
/// A delegate provided by the user of this class which returns the current state,
/// to be tested against a certain condition in the IsConditionMet delegate.
public delegate T RequestState();
public RequestState RequestStateDelegate { get; set; }
/// A delegate provided by the user of this class which determines whether given the
/// current state, the polling program should execute the ConditionMet delegate.
public delegate bool IsConditionMet(T state);
public IsConditionMet IsConditionMetDelegate { get; set; }
/// A delegate used to handle ConditionMonitor events.
public delegate void ConditionMonitorHandler(ConditionMonitor source, T state);
/// An event which fires each time the state is polled (use sparingly).
public event ConditionMonitorHandler RequestReceived;
/// An event which fires when the condition is met.
public event ConditionMonitorHandler ConditionM
Solution
I want to do this in a way that consumes minimal resources
Then don't have a separate thread that's not doing anything most of the time. Each thread in .Net consumes 1 MB of memory (both virtual and physical) and some other resources. A better solution would be to run your code on the ThreadPool and don't use
I just want to be sure I haven't set this up in a way where I risk spinning off more than a single thread […]
Actually, there is a chance exactly that will happen if two threads called
[…] or end up with a thread that keeps running even after StopMonitoring has been called.
I think that is also a possibility. The check of
Is there anything else I need to do to clean up the thread, or is simply letting
Yes, that is sufficient, just let the method return and the thread will be safely destroyed.
I'm also worried about what happens if someone abandons the
The GC would do no such thing. The thread you created does have a reference to the instance, so the GC won't “dispose” it. (I use quotes, because disposing in .Net usually means calling
A solution here might be to have another object that isn't referenced from
Also, it seems to me you're using
Then don't have a separate thread that's not doing anything most of the time. Each thread in .Net consumes 1 MB of memory (both virtual and physical) and some other resources. A better solution would be to run your code on the ThreadPool and don't use
Thread.Sleep(). The best way to do this is to use a Timer.I just want to be sure I haven't set this up in a way where I risk spinning off more than a single thread […]
Actually, there is a chance exactly that will happen if two threads called
BeginMonitoring() at the same time. Could that happen in your situation?[…] or end up with a thread that keeps running even after StopMonitoring has been called.
I think that is also a possibility. The check of
Halted might be optimized away, you should mark it as volatile, to make sure that doesn't happen.Is there anything else I need to do to clean up the thread, or is simply letting
PollState return sufficient?Yes, that is sufficient, just let the method return and the thread will be safely destroyed.
I'm also worried about what happens if someone abandons the
ConditionMonitor instance without remembering to call StopMonitoring(). The GC would dispose of the class, but what would happen to the thread is spun up - would it get silently aborted, or throw a huge fuss since it references ConditionMonitor properties?The GC would do no such thing. The thread you created does have a reference to the instance, so the GC won't “dispose” it. (I use quotes, because disposing in .Net usually means calling
IDisposable.Dispose(), that's not what I'm talking about here.) But because of that, the thread would run indefinitely. And a finalizer wouldn't help you either, again because the GC won't touch the instance, because it's still referenced.A solution here might be to have another object that isn't referenced from
PollState() and that would make sure the thread is stopped in its finalizer.Also, it seems to me you're using
virtual too much. It's meant only for methods that you really want to have overridden. And, actually private virtual doesn't make sense and should cause a compile error. Similarly, the default visibility for fields (and non-public methods) should be private, not protected.Context
StackExchange Code Review Q#13357, answer score: 9
Revisions (0)
No revisions yet.