Pass System.Threading.Timer object reference to its callback function - c#

is it possible to pass the System.Threading.Timer object reference to its callback function, something like this:
System.Threading.Timer myTimer = new System.Threading.Timer(new TimerCallback(DoSomething), myTimer, 2000, Timeout.Infinite);
Because in "DoSomething" method I want to call:
myTimer.Change(5000, Timeout.Infinite);
I'll paste a draft console application below.
Idea is this: I have List of timers. And every timer makes some request and when it receives it, it changes some shared data.
But, I can't pass the reference to timer into its callback, nor can I use it's index, because it becomes "-1" for some reason(investigating)..
using System;
using System.Collections.Generic;
using System.Threading;
namespace TimersInThreads
{
class Program
{
public static int sharedDataInt;
static private readonly object lockObject = new object();
public static List<System.Threading.Timer> timers = new List<Timer>();
static void Main(string[] args)
{
System.Threading.Timer timer = new System.Threading.Timer(new TimerCallback(DoSomething), timers.Count - 1, 2000, Timeout.Infinite);
timers.Add(timer);
System.Threading.Timer timer2 = new System.Threading.Timer(new TimerCallback(DoSomething), timers.Count - 1, 2000, Timeout.Infinite);
timers.Add(timer2);
System.Threading.Timer timer3 = new System.Threading.Timer(new TimerCallback(DoSomething), timers.Count - 1, 2000, Timeout.Infinite);
timers.Add(timer3);
//timer = new System.Threading.Timer(new TimerCallback(DoSomething), "Timer 1", 1000, Timeout.Infinite);
//timer = new System.Threading.Timer(new TimerCallback(DoSomething), "Timer 2", 450, Timeout.Infinite);
//timer = new System.Threading.Timer(new TimerCallback(DoSomething), "Timer 3", 1500, Timeout.Infinite);
Console.ReadLine();
}
static void DoSomething(object timerIndex)
{
// Request
// Get Response
var x = getSomeNumberWithDelay();
// Executes after Response is received
lock (lockObject)
{
sharedDataInt++;
Console.WriteLine("Timer" + (int)timerIndex + ", SHaredDataInt: " + sharedDataInt + "\t\t" + DateTime.Now.ToString("HH:mm:ss tt") + "." + DateTime.Now.Millisecond.ToString());
}
timers[(int)timerIndex].Change(5000, Timeout.Infinite);
}
static int getSomeNumberWithDelay()
{
Thread.Sleep(5000);
return 3;
}
}
}
Please, give me some idea or advice.
Much appreciated, thanks!

The state parameter in the Timer constructor is passed as an argument to the TimerCallback - this is just an object therefore will work with anything, including the timer reference itself.
So
new System.Threading.Timer(new TimerCallback(DoSomething), myTimer, 2000, Timeout.Infinite);
is perfectly acceptable. In your callback you would just need to cast the parameter as Timer e.g.
static void DoSomething(object state)
{
...
var timer = (System.Threading.Timer)state;
}
Looking at your problem again, I see what you are trying to do is pass the timer as a parameter into it's constructor (which obviously can't be done as it hasn't been officially declared yet). You can workaround this though by passing the timer to the callback explicitly e.g.
Timer t = null;
t = new Timer(delegate { DoSomething(t); }, null, 2000, Timeout.Infinite);
By the time the callback is triggered t will set to the reference of the timer.

Replace each occurrence of timers.Count - 1 with timers.Count:
System.Threading.Timer timer = new System.Threading.Timer(new TimerCallback(DoSomething), timers.Count, 2000, Timeout.Infinite);
timers.Add(timer);
When you adding first timer to the list, there is no elements there, so the timers.Count equals to 0.
Alternative way is to pass an instance of particular timer as the second argument of the callback instead of its index.

I have a class for this purpose. It provides a TypedCallback, with State, and a reference to the Timer. The class maintains a List of references and provides Disposal.
I don't have enough "points" to make comments, but also wanted to point out that in James' answer, you need to be sure to retain a reference to the Timer. As the documentation states, they can become garbage even if still running.
/// <summary>
/// Holds a list of references to Timers; and provides typed objects to reference the Timer and its
/// State from within a TypedCallback. Synchronized. Usage:
/// <code>
/// TypedStateTimers myTimers = new TypedStateTimers(3);
/// public void MyMethod() {
/// typedStateTimers.Create("Hello, from Timer", new TypedCallback<string>((sr) => {
/// System.Console.WriteLine(sr.State); // "Hello, from Timer"
/// sr.Dispose(); // Invoke the StateRef method to ensure references are released
/// })).Start(1500, Timeout.Infinite);
/// }
/// </code>
/// </summary>
public class TypedStateTimers
{
/// <summary>
/// A typed delegate used as the callback when Timers are created.
/// </summary>
public delegate void TypedCallback<T>(StateRef<T> state);
/// <summary>
/// Wraps a Timer and State object to be used from within a TypedCallback.
/// </summary>
public class StateRef<T> : IDisposable
{
/// <summary>The state passed into TypedStateTimers.Create. May be null.</summary>
public T State { get; internal set; }
/// <summary>The Timer: initially not started. Not null.</summary>
public System.Threading.Timer Timer { get; internal set; }
/// <summary>The TypedStateTimers instance that created this object. Not null.</summary>
public TypedStateTimers Parent { get; internal set; }
/// <summary>
/// A reference to this object is retained; and then Timer's dueTime and period are changed
/// to the arguments.
/// </summary>
public void Start(int dueTime, int period) {
lock (Parent.Treelock) {
Parent.Add(this);
Timer.Change(dueTime, period);
}
}
/// <summary>Disposes the Timer; and releases references to Timer, State, and this object.</summary>
public void Dispose() {
lock (Parent.Treelock) {
if (Timer == null) return;
Timer.Dispose();
Timer = null;
State = default(T);
Parent.Remove(this);
}
}
}
internal readonly object Treelock = new object();
private readonly List<IDisposable> stateRefs;
/// <summary>
/// Constructs an instance with an internal List of StateRef references set to the initialCapacity.
/// </summary>
public TypedStateTimers(int initialCapacity) {
stateRefs = new List<IDisposable>(initialCapacity);
}
/// <summary>Invoked by the StateRef to add it to our List. Not Synchronized.</summary>
internal void Add<T>(StateRef<T> stateRef) {
stateRefs.Add(stateRef);
}
/// <summary>Invoked by the StateRef to remove it from our List. Not synchronized.</summary>
internal void Remove<T>(StateRef<T> stateRef) {
stateRefs.Remove(stateRef);
}
/// <summary>
/// Creates a new StateRef object containing state and a new Timer that will use the callback and state.
/// The Timer will initially not be started. The returned object will be passed into the callback as its
/// argument. Start the Timer by invoking StateRef.Start. Dispose the Timer, and release references to it,
/// state, and the StateRef by invoking StateRef.Dispose. No references are held on the Timer, state or
/// the StateRef until StateRef.Start is invoked. See the class documentation for a usage example.
/// </summary>
public StateRef<T> Create<T>(T state, TypedCallback<T> callback) {
StateRef<T> stateRef = new StateRef<T>();
stateRef.Parent = this;
stateRef.State = state;
stateRef.Timer = new System.Threading.Timer(
new TimerCallback((s) => { callback.Invoke((StateRef<T>) s); }),
stateRef, Timeout.Infinite, Timeout.Infinite);
return stateRef;
}
/// <summary>Disposes all current StateRef instances; and releases all references.</summary>
public void DisposeAll() {
lock (Treelock) {
IDisposable[] refs = stateRefs.ToArray();
foreach (IDisposable stateRef in refs) stateRef.Dispose();
}
}
}

Related

Which is the best way to release thread that uses BlockingCollection?

I have a class that uses BlockingCollection like this:
public class Logger : IDisposable
{
private BlockingCollection<LogMessage> _messages = null;
private Thread _worker = null;
private bool _started = false;
public void Start()
{
if (_started) return;
//Some logic to open log file
OpenLogFile();
_messages = new BlockingCollection<LogMessage>(); //int.MaxValue is the default upper-bound
_worker = new Thread(Work) { IsBackground = true };
_worker.Start();
_started = true;
}
public void Stop()
{
if (!_started) return;
// prohibit adding new messages to the queue,
// and cause TryTake to return false when the queue becomes empty.
_messages.CompleteAdding();
// Wait for the consumer's thread to finish.
_worker.Join();
//Dispose managed resources
_worker.Dispose();
_messages.Dispose();
//Some logic to close log file
CloseLogFile();
_started = false;
}
/// <summary>
/// Implements IDiposable
/// In this case, it is simply an alias for Stop()
/// </summary>
void IDisposable.Dispose()
{
Stop();
}
/// <summary>
/// This is message consumer thread
/// </summary>
private void Work()
{
LogMessage message;
//Try to get data from queue
while(_messages.TryTake(out message, Timeout.Infinite))
WriteLogMessage(message); //... some simple logic to write 'message'
}
}
I create a new instance of the Logger class, call its Start() method. Then, if I forget to call the Dispose method when the instance is no longer referenced, then the Worker Thread will never end. That's a kind of memory leak. Am I right? and how to overcome this?
You may try to keep only a weak reference to the BlockingCollection in your worker thread and do not reference an object that is referencing the BlockingCollection. I made a static method to ensure that we don't reference the Logger instance this.
This way the collection can be finalized/collected when it is no longer referenced. I'm not sure it'll work, you have to try, It depends on whether TryTake keeps the collection alive or not. It may not work in debug as the GC behave differently, so try it in release without debugger attached.
public class Logger : IDisposable
{
private BlockingCollection<LogMessage> _messages = null;
private Thread _worker = null;
private bool _started = false;
public void Start()
{
if (_started) return;
//Some logic to open log file
OpenLogFile();
_messages = new BlockingCollection<LogMessage>(); //int.MaxValue is the default upper-bound
_worker = new Thread(Work) { IsBackground = true };
_worker.Start(new WeakReference<BlockingCollection<LogMessage>>(_messages));
_started = true;
}
public void Stop()
{
if (!_started) return;
// prohibit adding new messages to the queue,
// and cause TryTake to return false when the queue becomes empty.
_messages.CompleteAdding();
// Wait for the consumer's thread to finish.
_worker.Join();
//Dispose managed resources
_worker.Dispose();
_messages.Dispose();
//Some logic to close log file
CloseLogFile();
_started = false;
}
/// <summary>
/// Implements IDiposable
/// In this case, it is simply an alias for Stop()
/// </summary>
void IDisposable.Dispose()
{
Stop();
}
/// <summary>
/// This is message consumer thread
/// </summary>
private static void Work(object state)
{
LogMessage message;
//Try to get data from queue
do
{
BlockingCollection<LogMessage> messages;
if (((WeakReference<BlockingCollection<LogMessage>>)state).TryGetTarget(out messages)
&& messages.TryTake(out message, Timeout.Infinite))
{
WriteLogMessage(message); //... some simple logic to write 'message'
continue;
}
} while (false);
}
}

Timer in portable class library

I've made a timer class based on this discussion but I have a problem with it, the elapsed event occurs only one time.
The smaller issue: It would be a good thing if the _timer not have to be instantiated at every calling of Start().
using System;
using System.Threading;
using System.Threading.Tasks;
using System.Diagnostics.Contracts;
namespace JellystonePark.Model
{
internal delegate void TimerCallback(object state);
internal sealed class Timer : CancellationTokenSource, IDisposable
{
internal Timer(TimerCallback callback, object state, TimeSpan dueTime, TimeSpan period)
{
Contract.Assert(period == TimeSpan.FromMilliseconds(-1), "This stub implementation only supports dueTime.");
Task.Delay(dueTime, Token).ContinueWith((t, s) =>
{
var tuple = (Tuple<TimerCallback, object>)s;
tuple.Item1(tuple.Item2);
}, Tuple.Create(callback, state), CancellationToken.None,
TaskContinuationOptions.ExecuteSynchronously | TaskContinuationOptions.OnlyOnRanToCompletion,
TaskScheduler.Default);
}
public new void Dispose() { base.Cancel(); }
}
public class PCLTimer
{
private Timer _timer;
private TimeSpan _interval;
/// <summary>
/// Interval between signals in milliseconds.
/// </summary>
public double Interval
{
get { return _interval.TotalMilliseconds; }
set { _interval = TimeSpan.FromMilliseconds(value); Stop(); Start(); }
}
/// <summary>
/// True if PCLTimer is running, false if not.
/// </summary>
public bool Enabled
{
get { return null != _timer; }
set { if (value) Start(); else Stop(); }
}
/// <summary>
/// Occurs when the specified time has elapsed and the PCLTimer is enabled.
/// </summary>
public event EventHandler Elapsed;
/// <summary>
/// Starts the PCLTimer.
/// </summary>
public void Start()
{
if (0 == _interval.TotalMilliseconds)
throw new InvalidOperationException("Set Elapsed property before calling PCLTimer.Start().");
_timer = new Timer(OnElapsed, null, _interval, _interval);
}
/// <summary>
/// Stops the PCLTimer.
/// </summary>
public void Stop()
{
_timer.Dispose();
}
/// <summary>
/// Releases all resources.
/// </summary>
public void Dispose()
{
_timer.Dispose();
}
/// <summary>
/// Invokes Elapsed event.
/// </summary>
/// <param name="state"></param>
private void OnElapsed(object state)
{
if (null != _timer && null != Elapsed)
Elapsed(this, EventArgs.Empty);
}
}
}
If you interested in implementing Timer with Tasks, you can try this code:
public delegate void TimerCallback(object state);
public sealed class Timer : CancellationTokenSource, IDisposable
{
public Timer(TimerCallback callback, object state, int dueTime, int period)
{
Task.Delay(dueTime, Token).ContinueWith(async (t, s) =>
{
var tuple = (Tuple<TimerCallback, object>) s;
while (true)
{
if (IsCancellationRequested)
break;
Task.Run(() => tuple.Item1(tuple.Item2));
await Task.Delay(period);
}
}, Tuple.Create(callback, state), CancellationToken.None,
TaskContinuationOptions.ExecuteSynchronously | TaskContinuationOptions.OnlyOnRanToCompletion,
TaskScheduler.Default);
}
public new void Dispose() { base.Cancel(); }
}
As already mentioned you can introduce dependency on some interface and ask user to give you particular timer implementation.

Ensuring execution order between multiple threads

I am having a kinda annoying problem mostly due to my low skill level/experience in C# multithreading.
Here is the background. In my framework, I have a static class named WaitFormHelper, which has two static methods (well... actually more but we don't care here), Start() and Close()
The Start() method initializes and starts a thread which will acquire a lock on the locker object and create a WaitForm (which is a small loading control with a custom message and a progress bar)
In my current project, I have a method which starts a WaitForm, performs calculations, then closes the WaitForm. Nothing fancy at all.
The method looks like the following, I simplified it as much as possible:
public void PerformCalculations()
{
try
{
WaitFormHelper.Start("Title", "message", false);
if (this.CalculationsParameters.IsInvalid)
{
return;
}
// Perform all those lengthy calculations here
}
// catch whatever exception I may have to catch, we don't care here
finally
{
WaitFormHelper.Close();
}
}
Here are the Start() and Close() methods with related methods & attributes, simplified as well:
private static Thread instanceCaller;
private static WaitForm instance;
private static AutoResetEvent waitFormStarted = new AutoResetEvent(false);
private static object locker = new object();
/// <summary>
/// Initializes WaitForm to start a single task
/// </summary>
/// <param name="header">WaitForm header</param>
/// <param name="message">Message displayed</param>
/// <param name="showProgressBar">True if we want a progress bar, else false</param>
public static void Start(string header, string message, bool showProgressBar)
{
InitializeCallerThread(showProgressBar, header, message);
instanceCaller.Start();
}
/// <summary>
/// Initializes caller thread for executing a single command
/// </summary>
/// <param name="showProgressBar"></param>
/// <param name="header"></param>
/// <param name="message"></param>
private static void InitializeCallerThread(bool showProgressBar, string header, string message)
{
waitFormStarted.Reset();
instanceCaller = new Thread(() =>
{
lock (locker)
{
instance = new WaitForm()
{
Header = header,
Message = message,
IsProgressBarVisible = showProgressBar
};
waitFormStarted.Set();
}
instance.ShowDialog();
});
instanceCaller.Name = "WaitForm thread";
instanceCaller.SetApartmentState(ApartmentState.STA);
instanceCaller.IsBackground = true;
}
/// <summary>
/// Closes current form
/// </summary>
public static void Close()
{
lock (locker)
{
if (instance != null && !instance.IsClosed)
{
waitFormStarted.WaitOne();
instance.FinalizeWork();
instance.Dispatcher.Invoke(
new Action(() =>
{
instance.Close();
}));
}
}
}
Now let's get to the problem
This usually works fine, except in this case:
If this.CalculationsParameters.IsInvalid is true (ie. as you probably already understood, I can't perform calculations for some reason, such as "user entering crap in my forms"), the execution directly closes my WaitForm.
However in this case, the main thread will reach the Close method and acquire a lock on the locker object before the thread fired by the Start() method.
What happens is that: Close acquires lock, tries to close the form but instance is still null because the Thread created in InitializeCallerThread is still waiting for the lock to actually create it. Close releases lock, InitializeCallerThread acquires it and... shows a WaitForm which will not close.
Now I know that I can simply fix this problem by testing if the calculation parameters are invalid before actually starting the WaitForm, but well, problem is this WaitForm is supposed to be used by all applications of our framework (which includes 40+ different apps used and maintained in 4 countries), so ideally I'd rather prefer seeing my WaitForm working at all cases.
Do you have any idea on how could I synchronize this to make sure the starter thread is definitely called and executed first?
As you can see I already use an AutoResetEvent for this matter, but if I listen to it before the test if (instance != null) I will end up stuck in my case.
Hope this is clear enough! Thank you!
You need some mechanism to make a "queue control", coordinating steps according to the order you want them occurring.
Recently I have needed to implement something like this to force a specific order in the execution of several threads in a unit test.
Here is my suggestion:
QueueSynchronizer:
/// <summary>
/// Synchronizes steps between threads.
/// </summary>
public class QueueSynchronizer
{
/// <summary>
/// Constructor.
/// </summary>
/// <param name="minWait">Minimum waiting time until the next try.</param>
/// <param name="maxWait">Maximum waiting time until the next try.</param>
public QueueSynchronizer(Int32 minWait, Int32 maxWait)
{
}
private Mutex mx = new Mutex();
/// <summary>
/// Minimum waiting time until the next try.
/// </summary>
private Int32 minWait = 5;
/// <summary>
/// Maximum waiting time until the next try.
/// </summary>
private Int32 maxWait = 500;
int currentStep = 1;
/// <summary>
/// Key: order in the queue; Value: Time to wait.
/// </summary>
private Dictionary<int, int> waitingTimeForNextMap = new Dictionary<int, int>();
/// <summary>
/// Synchronizes by the order in the queue. It starts from 1. If is not
/// its turn, the thread waits for a moment, after that, it tries again,
/// and so on until its turn.
/// </summary>
/// <param name="orderInTheQueue">Order in the queue. It starts from 1.</param>
/// <returns>The <see cref="Mutex"/>The mutex that must be released at the end of turn.
/// </returns>
public Mutex Sincronize(int orderInTheQueue)
{
do
{
//while it is not the turn, the thread will stay in this loop and sleeping for 100, 200, ... 1000 ms
if (orderInTheQueue != this.currentStep)
{
//The next in queue will be waiting here (other threads).
mx.WaitOne();
mx.ReleaseMutex();
//Prevents 100% processing while the current step does not happen
if (!waitingTimeForNextMap.ContainsKey(orderInTheQueue))
{
waitingTimeForNextMap[orderInTheQueue] = this.minWait;
}
Thread.Sleep(waitingTimeForNextMap[orderInTheQueue]);
waitingTimeForNextMap[orderInTheQueue] = Math.Min(waitingTimeForNextMap[orderInTheQueue] * 2, this.maxWait);
}
} while (orderInTheQueue != this.currentStep);
mx.WaitOne();
currentStep++;
return mx;
}
}
Start() and Close() with QueueSynchronizer:
//synchronizer
private static QueueSynchronizer queueSynchronizer;
private static Thread instanceCaller;
private static WaitForm instance;
private static AutoResetEvent waitFormStarted = new AutoResetEvent(false);
private static object locker = new object();
/// <summary>
/// Initializes WaitForm to start a single task
/// </summary>
/// <param name="header">WaitForm header</param>
/// <param name="message">Message displayed</param>
/// <param name="showProgressBar">True if we want a progress bar, else false</param>
public static void Start(string header, string message, bool showProgressBar)
{
queueSynchronizer = new QueueSynchronizer();
InitializeCallerThread(showProgressBar, header, message);
instanceCaller.Start();
}
/// <summary>
/// Initializes caller thread for executing a single command
/// </summary>
/// <param name="showProgressBar"></param>
/// <param name="header"></param>
/// <param name="message"></param>
private static void InitializeCallerThread(bool showProgressBar, string header, string message)
{
waitFormStarted.Reset();
instanceCaller = new Thread(() =>
{
lock (locker)
{
//Queuing to run on first.
Mutex mx = queueSynchronizer.Sincronize(1);
try
{
instance = new WaitForm()
{
Header = header,
Message = message,
IsProgressBarVisible = showProgressBar
};
}
finally
{
//I think is here that ends the first step!?
mx.ReleaseMutex();
}
waitFormStarted.Set();
}
instance.ShowDialog();
});
instanceCaller.Name = "WaitForm thread";
instanceCaller.SetApartmentState(ApartmentState.STA);
instanceCaller.IsBackground = true;
}
/// <summary>
/// Closes current form
/// </summary>
public static void Close()
{
//Queuing to run on second.
Mutex mx = queueSynchronizer.Sincronize(2);
try
{
lock (locker)
{
if (instance != null && !instance.IsClosed)
{
waitFormStarted.WaitOne();
instance.FinalizeWork();
instance.Dispatcher.Invoke(
new Action(() =>
{
instance.Close();
}));
}
}
}
finally
{
mx.ReleaseMutex();
}
}
You need to Join on the thread that you created. By joining on a thread you'll block at that point until the thread has finished executing.
public static void Close()
{
lock (locker)
{
instanceCaller.Join();
if (instance != null && !instance.IsClosed)
{
waitFormStarted.WaitOne();
instance.FinalizeWork();
instance.Dispatcher.Invoke(
new Action(() =>
{
instance.Close();
}));
}
}
}

C# While Loop in Worker Thread for listening command and response

Overview of the problem:
I try to use a thread (while..loop) to listen a command from user. If user send a command, it will assign new value in the global variable which is in the class (LoopingWorkerThread).
I don't understand if I don't put the thread sleep value lower than 10 milliseconds, and I wouldn't get any response (it is in the ListenCommand method) . Look like the global parameter is being overwritten "_CommandReceived" in the method, probably the processor run to fast and ignore the value of the parameter had changed ("_CommandReceived").
Kindly comment if there is any better mechanism. I had lock it in the ListenCommand while loop.
The following are the codes:
public class LoopingWorkerThread
{
/// <summary>
/// Local main thread for LoopingWorkerThread
/// </summary>
private Thread t;
/// <summary>
/// Local parameter to identify the LoopingWorkerThread Is On
/// </summary>
private bool _IsOn;
/// <summary>
/// Local parameter to store command received from user
/// </summary>
private int _CommandReceived;
/// <summary>
/// Local object to use for locking the LoopingWorker Thread
/// </summary>
private object _LockListenCommand = new object();
/// <summary>
/// Properties of LoopingWorker Thread Is On
/// </summary>
public bool IsOn
{
get { return _IsOn; }
set { _IsOn = value; }
}
/// <summary>
/// Property of storing the command received from user
/// </summary>
public int CommandReceived
{
get { return _CommandReceived; }
set { _CommandReceived = value; }
}
/// <summary>
/// Delegate for OnResponse Event Handler
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
public delegate void OnResponseHandler(object sender, ResponseArg e);
/// <summary>
/// Event of OnResponse
/// </summary>
public event OnResponseHandler OnResponse;
/// <summary>
/// Constructor of LoopingWorkerThread Class
/// </summary>
public LoopingWorkerThread()
{
_IsOn = false;
}
/// <summary>
/// Method of LoopingWorkerThread Function
/// </summary>
private void ListenCommand()
{
lock (_LockListenCommand)
while (_IsOn)
{
switch (_CommandReceived)
{
case 0:
// Ignore default command
break;
case 1:
FireOnResponse("Received cmd 1, response [Hello One]");
break;
case 2:
FireOnResponse("Received cmd 2, response [Hello Two]");
break;
default:
FireOnResponse("Error. Received unidentified command - " + _CommandReceived.ToString());
break;
}
//Console.WriteLine("ThreadProc: Cmd:[{0}] - Response:{1}", _CommandReceived.ToString(), ReaderResponse);
// Reset or Clear the Command Received
_CommandReceived = 0;
// If the sleep less than 10 millisecond, it always don't catch the
// command received which assigned to 1 or 2. Don't understand, or is there
// any better method.
**Thread.Sleep(10);**
}
}
/// <summary>
/// Function of firing response event back to user
/// </summary>
/// <param name="message"></param>
private void FireOnResponse(string message)
{
ResponseArg myarg = new ResponseArg(message);
if (OnResponse != null)
OnResponse(this, myarg);
}
/// <summary>
/// Method of starting the LoopingWorkerThread
/// </summary>
public void Start()
{
_IsOn = true;
FireOnResponse("Main thread: Started.");
// The constructor for the Thread class requires a ThreadStart
// delegate that represents the method to be executed on the
// thread. C# simplifies the creation of this delegate.
t = new Thread(new ThreadStart(ListenCommand));
// Start ThreadProc. Note that on a uniprocessor, the new
// thread does not get any processor time until the main thread
// is preempted or yields. Uncomment the Thread.Sleep that
// follows t.Start() to see the difference.
t.Start();
//Thread.Sleep(0);
FireOnResponse("Main thread: Call Start().");
}
/// <summary>
/// Method of stopping the LoopingWorkerThread
/// </summary>
public void Stop()
{
_IsOn = false;
t.Join();
//t.Abort();
FireOnResponse("LoopingWorker Thread is stopped.");
}
/// <summary>
/// Method of sending command to the LoopingWorkerThread
/// </summary>
/// <param name="readercmd"></param>
public void SendCommand(int readercmd)
{
_CommandReceived = readercmd;
}
}
Your code works because Thread.Sleep produces the necessary memory barrier required to read _commandReceived correctly. If you remove the Thread.Sleep call then you also remove the implicit memory barrier. Obviously, this is not a good mechanism to rely on though.
More importantly you are going about this the wrong way. What you should be using is the producer-consumer pattern. This is pretty easy with the BlockingCollection class since it blocks the consumer on Take while the queue is empty.
public class Example
{
private BlockingCollection<int> commands = new BlockingCollection<int>();
public Example()
{
var thread = new Thread(Run);
thread.IsBackground = true;
thread.Start();
}
public void SendCommmand(int command)
{
commands.Add(command);
}
private void Run()
{
while (true)
{
int command = commands.Take();
ProcessCommand(command);
}
}
private void ProcessCommand(int command)
{
// Process the command here.
}
}
BlockingCollection is available for 3.5 as part of the Reactive Extensions download.
Try declaring the variable volatile. More about this on http://msdn.microsoft.com/en-us/library/x13ttww7.aspx

Using AutoResetEvent to signal worker thread

I have a service that is running constantly processing data, it receives requests to process new data through messaging. While it's busy processing new requests get merged together so that they are then all processed at once. An AutoResetEvent is used to notify the processor that a new request is available.
My question is in EventLoop should it be possible that currentRequest after the WaitOne to be null?
Is it bad practice to have the _eventAvailable.Set() outside of the lock(_eventLocker)? I moved it out so that it wouldn't start going at the WaitOne and immediately contest the lock(_eventLocker).
Any suggestions on how to better write the following code?
public sealed class RealtimeRunner : MarshalByRefObject
{
/// <summary>
/// The actual event, new events get merged into this if it is not null
/// </summary>
private Request _pendingRequest;
/// <summary>
/// Used to signal the runner thread when an event is available to process
/// </summary>
private readonly AutoResetEvent _eventAvailable = new AutoResetEvent(false);
private readonly object _eventLocker = new object();
/// <summary>
/// Called on a background thread via messaging
/// </summary>
public void QueueEvent(RealtimeProcessorMessage newRequest)
{
bool mergedRequest;
lock (_eventLocker)
{
if (_pendingRequest == null)
{
mergedRequest = false;
_pendingRequest = new Request(newRequest, _engine);
}
else
{
mergedRequest = true;
_pendingRequest.Merge(newRequest, _engine);
}
}
_eventAvailable.Set();
}
/// <summary>
/// This is running on its own thread
/// </summary>
private void EventLoop()
{
while (true)
{
// Block until something exists in _pendingRequest
_eventAvailable.WaitOne();
Request currentRequest;
lock (_eventLocker)
{
currentRequest = _pendingRequest;
_pendingRequest = null;
}
// CAN THIS EVER BE NULL?
if (currentRequest == null)
continue;
//do stuff with the currentRequest here
}
}
}
Yes, the if (currrentRequest == null) could evaluate to true. Consider two threads racing to call _eventAvailable.Set(). One completes the call and the other gets preempted. Meanwhile the EventLoop thread wakes up and completes an entire iteration of the loop. You now have a situation where _pendingRequest is null and the WaitHandle is still waiting to be signaled again.
I want to present an entirely different solution to the problem. It looks your code could be simplified by using the producer-consumer pattern. This pattern is most easily implemented using a blocking queue. The BlockingCollection class implements such a queue.
public sealed class RealtimeRunner : MarshalByRefObject
{
private BlockingCollection<Request> m_Queue = new BlockingCollection<Request>();
public void QueueEvent(RealtimeProcessorMessage newRequest)
{
m_Queue.Add(new Request(newRequest _engine));
}
private void EventLoop()
{
while (true)
{
// This blocks until an item appears in the queue.
Request request = m_Queue.Take();
// Process the request here.
}
}
}

Categories