I have a function that I want to invoke every x seconds, but I want it to be thread-safe.
Can I set up this behavior when I am creating the timer? (I don't mind which .NET timer I use, I just want it to be thread-safe).
I know I can implement locks inside my callback function, but I think it would be more elegant if it were in the timer level.
My callback function, and environment are not related to a UI.
[Edit 1]
I just don't want there to be more than one thread inside my callback function.
[Edit 2]
I want to keep the locking inside the timer level, because the timer is responsible for when to call my callback, and here there is a particular situation when I don't want to call my callback function. So I think when to call is the responsibility of the timer.
I'm guessing, as your question is not entirely clear, that you want to ensure that your timer cannot re-enter your callback whilst you are processing a callback, and you want to do this without locking. You can achieve this using a System.Timers.Timer and ensuring that the AutoReset property is set to false. This will ensure that you have to trigger the timer on each interval manually, thus preventing any reentrancy:
public class NoLockTimer : IDisposable
{
private readonly Timer _timer;
public NoLockTimer()
{
_timer = new Timer { AutoReset = false, Interval = 1000 };
_timer.Elapsed += delegate
{
//Do some stuff
_timer.Start(); // <- Manual restart.
};
_timer.Start();
}
public void Dispose()
{
if (_timer != null)
{
_timer.Dispose();
}
}
}
Complementing Tim Lloyd's solution for System.Timers.Timer, here's a solution to prevent reentrancy for cases where you want to use System.Threading.Timer instead.
TimeSpan DISABLED_TIME_SPAN = TimeSpan.FromMilliseconds(-1);
TimeSpan interval = TimeSpan.FromSeconds(1);
Timer timer = null; // assign null so we can access it inside the lambda
timer = new Timer(callback: state =>
{
doSomeWork();
try
{
timer.Change(interval, DISABLED_TIME_SPAN);
}
catch (ObjectDisposedException timerHasBeenDisposed)
{
}
}, state: null, dueTime: interval, period: DISABLED_TIME_SPAN);
I believe you don't want interval to be accessed inside of the callback, but that is be easy to fix, if you want to: Put the above into a NonReentrantTimer class that wraps the BCL's Timer class. You would then pass the doSomeWork callback in as a parameter. An example of such a class:
public class NonReentrantTimer : IDisposable
{
private readonly TimerCallback _callback;
private readonly TimeSpan _period;
private readonly Timer _timer;
public NonReentrantTimer(TimerCallback callback, object state, TimeSpan dueTime, TimeSpan period)
{
_callback = callback;
_period = period;
_timer = new Timer(Callback, state, dueTime, DISABLED_TIME_SPAN);
}
private void Callback(object state)
{
_callback(state);
try
{
_timer.Change(_period, DISABLED_TIME_SPAN);
}
catch (ObjectDisposedException timerHasBeenDisposed)
{
}
}
public void Dispose()
{
_timer.Dispose();
}
}
I know I can implement locks inside my callback function, but I think it will be more elegant if it will be in the timer level
If locking is necessary then how could a timer arrange that? You're looking for a magical freebie.
Re Edit1:
Your choices are System.Timers.Timer and System.Threading.Timer, both need precautions against re-entrance. See this page and look for the Dealing with Timer Event Reentrance section.
using System;
using System.Diagnostics;
/// <summary>
/// Updated the code.
/// </summary>
public class NicerFormTimer : IDisposable {
public void Dispose() {
using ( this.Timer ) { }
GC.SuppressFinalize( this );
}
private System.Windows.Forms.Timer Timer { get; }
/// <summary>
/// Perform an <paramref name="action" /> after the given interval (in <paramref name="milliseconds" />).
/// </summary>
/// <param name="action"></param>
/// <param name="repeat">Perform the <paramref name="action" /> again. (Restarts the <see cref="Timer" />.)</param>
/// <param name="milliseconds"></param>
public NicerFormTimer( Action action, Boolean repeat, Int32? milliseconds = null ) {
if ( action == null ) {
return;
}
this.Timer = new System.Windows.Forms.Timer {
Interval = milliseconds.GetValueOrDefault( 1000 )
};
this.Timer.Tick += ( sender, args ) => {
try {
this.Timer.Stop();
action();
}
catch ( Exception exception ) {
Debug.WriteLine( exception );
}
finally {
if ( repeat ) {
this.Timer.Start();
}
}
};
this.Timer.Start();
}
}
/// <summary>
/// Updated the code.
/// </summary>
public class NicerSystemTimer : IDisposable {
public void Dispose() {
using ( this.Timer ) { }
GC.SuppressFinalize( this );
}
private System.Timers.Timer Timer { get; }
/// <summary>
/// Perform an <paramref name="action" /> after the given interval (in <paramref name="milliseconds" />).
/// </summary>
/// <param name="action"></param>
/// <param name="repeat">Perform the <paramref name="action" /> again. (Restarts the <see cref="Timer" />.)</param>
/// <param name="milliseconds"></param>
public NicerSystemTimer( Action action, Boolean repeat, Double? milliseconds = null ) {
if ( action == null ) {
return;
}
this.Timer = new System.Timers.Timer {
AutoReset = false,
Interval = milliseconds.GetValueOrDefault( 1000 )
};
this.Timer.Elapsed += ( sender, args ) => {
try {
this.Timer.Stop();
action();
}
catch ( Exception exception ) {
Debug.WriteLine( exception );
}
finally {
if ( repeat ) {
this.Timer.Start();
}
}
};
this.Timer.Start();
}
}
How timer could know about your shared data?
Timer callback is executed on some ThreadPool thread. So you will have at least 2 threads:
Your main thread where timer is created and launched;
Thread from ThreadPool for launching callback.
And it is your responsibility to provide correct work with your shared data.
Re edits: chibacity provided the perfect example.
Related
Do WPF have Touch-and-Hold gesture? I cannot find event for that, so I tried to implement one for myself. I know that there is Stylus class but in WPF it does not help me. If there aren't one there is my code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Timers;
namespace WebControlTouch
{
/// <summary>
/// Due to lack of Touch-and-Hold gesture, here is implementation of it. Stupid M$.
/// </summary>
public static class Touch_and_Hold
{
#region Constructor + methods
/// <summary>
/// Static constructor which creates timer object with 1000ms interval, also sets parameters of Timer.
/// </summary>
static Touch_and_Hold()
{
gestureTimer = new Timer(1000);
gestureTimer.AutoReset = false;
gestureTimer.Elapsed += gestureTimer_Elapsed;
}
/// <summary>
/// On elasped (time ofc)
/// </summary>
/// <seealso cref="gestureTimer"/>
static void gestureTimer_Elapsed(object sender, ElapsedEventArgs e)
{
occured = true;
}
/// <summary>
/// Call it on OnTouchDown event.
/// It will start timer and will count time of touch
/// </summary>
/// <returns>Returns that gesture occured</returns>
public static void onTouch()
{
gestureTimer.Start();
}
/// <summary>
/// Call it on touch up mainwindow event (or somewhere else)
/// It stops gesture timer
/// </summary>
public static void onTouchUp()
{
occured = false;
}
#endregion
#region Members + properties
/// <summary>
/// Timer for measuring touchTime
/// </summary>
private static Timer gestureTimer;
/// <summary>
/// Do tap-and-hold occured
/// </summary>
private static bool occured = false;
/// <summary>
/// Property for getting occured flag
/// </summary>
public static bool occuredGesture
{
get { return occured; }
}
#endregion
}
}
If yes, please tell me name of the event. If not - try to steer me to solution.
Any help will be very appreciated.
It is possible to do that in an awaitable fashion. Create a timer with specific interval. Start it when user tapped and return the method when timer elapsed. If user release the hand, return the method with false flag.
public static Task<bool> TouchHold(this FrameworkElement element, TimeSpan duration)
{
DispatcherTimer timer = new DispatcherTimer();
TaskCompletionSource<bool> task = new TaskCompletionSource<bool>();
timer.Interval = duration;
MouseButtonEventHandler touchUpHandler = delegate
{
timer.Stop();
if (task.Task.Status == TaskStatus.Running)
{
task.SetResult(false);
}
};
element.PreviewMouseUp += touchUpHandler;
timer.Tick += delegate
{
element.PreviewMouseUp -= touchUpHandler;
timer.Stop();
task.SetResult(true);
};
timer.Start();
return task.Task;
}
For more information, read this post.
I've previously achieved this by create a custom control that extends button to delay the trigger of a button command after a delay on press-and-hold.
public class DelayedActionCommandButton : Button
First dependency properties:
public static readonly DependencyProperty DelayElapsedProperty =
DependencyProperty.Register("DelayElapsed", typeof(double), typeof(DelayedActionCommandButton), new PropertyMetadata(0d));
public static readonly DependencyProperty DelayMillisecondsProperty =
DependencyProperty.Register("DelayMilliseconds", typeof(int), typeof(DelayedActionCommandButton), new PropertyMetadata(1000));
public double DelayElapsed
{
get { return (double)this.GetValue(DelayElapsedProperty); }
set { this.SetValue(DelayElapsedProperty, value); }
}
public int DelayMilliseconds
{
get { return (int)this.GetValue(DelayMillisecondsProperty); }
set { this.SetValue(DelayMillisecondsProperty, value); }
}
These give us a control on how the delay should be and an output of how long is left.
Next I create an animation, to control the elapsed amount which when complete fires the command. There is also a cancel delay method:
private void BeginDelay()
{
this._animation = new DoubleAnimationUsingKeyFrames() { FillBehavior = FillBehavior.Stop };
this._animation.KeyFrames.Add(new EasingDoubleKeyFrame(0, KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(0)), new CubicEase() { EasingMode = EasingMode.EaseIn }));
this._animation.KeyFrames.Add(new EasingDoubleKeyFrame(1, KeyTime.FromTimeSpan(TimeSpan.FromMilliseconds(this.DelayMilliseconds)), new CubicEase() { EasingMode = EasingMode.EaseIn }));
this._animation.Completed += (o, e) =>
{
this.DelayElapsed = 0d;
this.Command.Execute(this.CommandParameter); // Replace with whatever action you want to perform
};
this.BeginAnimation(DelayElapsedProperty, this._animation);
}
private void CancelDelay()
{
// Cancel animation
this.BeginAnimation(DelayElapsedProperty, null);
}
Finally, we wire up the event handlers:
private void DelayedActionCommandButton_TouchDown(object sender, System.Windows.Input.TouchEventArgs e)
{
this.BeginDelay();
}
private void DelayedActionCommandButton_TouchUp(object sender, System.Windows.Input.TouchEventArgs e)
{
this.CancelDelay();
}
When used in XAML, you can optionally create a template that can animate based on the value of DelayElapsed to provide a countdown, or visual cue such as an expanding border, whatever takes your fancy.
I am creating an opc server with third party dll.they had given an example in which all functions r running on a different thread.
here is the example,OPCServer.cs:
public static OpcServer CreateInstanceAsync()
{
Thread thread = new Thread(new ParameterizedThreadStart(InitializationThread));
OpcServer opcServer = new OpcServer();
thread.Start(opcServer);
thread.Join();
return opcServer;
}
static void InitializationThread(object arg)
{
((OpcServer)arg).Initialize();
}
void Initialize()
{
//some stuff
}
public void UpdateValues(string[] n)
{
this.BeginUpdate();
value1 = (object[])n;
for (int i = 0; i < tag_count; i++)
{
this.SetTag(tag_ids[i], value1[i], Quality.Good, FileTime.UtcNow);
}
this.EndUpdate(false);
}
I am getting problem in the method UpdateValues();
in the main form:
public Form1()
{
InitializeComponent();
opcServer = OpcServer.CreateInstanceAsync();
opcServer.UpdateValues(valuesInArray);
}
there is a timer & the UpdateValues() method will call at every time tick with a new value. interval is 10 secs.
private void timer1_Tick(object sender, EventArgs e)
{
opcServer.UpdateValues(valuesInArray);
}
the program is running smoothly for some time. but after that it showing stack overflow exception.,sometimes pc got hanged.i don't understand why? how do i get rid from this? the OPCServer.cs is given by the 3rd party.my work is to passing value in that particular method.will i have to create a new thread each time i will call that method?
Try BackgroundWorker for updating form while running long process. Use ProgressChanged event to update the form values else invoke a delegate to update form controls.
Another alternative would be to use the Task Parallel Library and then use events and delegates to interact with form elements.
Using the Task Parallel Library is very easy:
foreach (DriveInfo info in DriveInfo.GetDrives())
{
if (info.DriveType == DriveType.Fixed)
{
var task = Task.Factory.StartNew(() => scanFiles(findType, info.RootDirectory.Name));
}
}
This would be an example of interacting with the form elements:
In my external class:
/// <summary>
/// Delegate for setting text box text
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
public delegate void TextBoxEventHandler(object sender, TextEventArgs e);
/// <summary>
/// Event for changing tool bar text
/// </summary>
public event TextBoxEventHandler ChangeTextBoxText = delegate { };
/// <summary>
/// Function that raises set tool bar text event
/// </summary>
/// <param name="s"></param>
public void SetTextBoxText(string s)
{
ChangeTextBoxText(this, new TextEventArgs(s));
}
In my form:
scanner.ChangeTextBoxText += scanner_ChangeTextBoxText;
private void scanner_ChangeTextBoxText(object sender, FS.TextEventArgs e)
{
addMessage(e.Message);
}
delegate void SetTextCallback(string text);
private void addMessage(string message)
{
if (edtContents.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(addMessage);
this.Invoke(d, new object[] { message });
}
else
{
edtContents.Text += String.Format("{0}{1}", message, Environment.NewLine);
edtContents.SelectionStart = edtContents.Text.Length;
edtContents.ScrollToCaret();
}
}
first of all why do you create a thread here
public static OpcServer CreateInstanceAsync()
{
Thread thread = new Thread(new ParameterizedThreadStart(InitializationThread));
OpcServer opcServer = new OpcServer();
thread.Start(opcServer);
thread.Join();
return opcServer;
}
because probably i think, you just don't want to hang your main form creation once you got the OpcServer object, you are just using the same instance to call the UpdateValues() in a timer.
now as you are piling things up in this call . how many updates you are adding.
this.SetTag(tag_ids[i], value1[i], Quality.Good, FileTime.UtcNow);
There must be some method to remove tags which are Old/Obsolete.
Check for the API documentation for freeing up the objects
How can I stop System.Threading.Timer in it's call back method. I referenced MSDN, but couldn't find anything useful. Please help.
First, the callback method must have the timer instance in-scope.
Then the simple incantation
timerInstance.Change( Timeout.Infinite , Timeout.Infinite ) ;
will shut down the timer. It is possible that the timer might invoke the callback method once more after the change, I believe, depending on the state it's in.
timer.Change(Timeout.Infinite, Timeout.Infinite);
Try this:
If you want you could let timer continue firing the callback method and include the code below
private void CreatorLoop(object state)
{
if (Monitor.TryEnter(lockObject)
{
try
{
// Work here
}
finally
{
Monitor.Exit(lockObject);
}
}
}
check out this link too:
Stopping timer in its callback method
You can simply call myTimer.Change(Timeout.Infinite, Timeout.Infinite).
Technically, only the first parameter (dueTime) needs to be specified as Timeout.Infinite for the timer to stop.
For more information, see Timer.Change Method.
I found out the hard way that Change(Timeout.Infinite, Timeout.Infinite) isn't quite reliable, and switched over to System.Timers.Timer with AutoReset = false.
The problem with Timer is that it might be called after disposing its owner class. The following implementation worked for me by using the state object of the Timer initializer. Heap will not remove that object until it is consumed. This was my only way to gracefully cleanup timer callback.
using System;
using System.Threading;
namespace TimerDispose
{
/// <summary>
/// A timer-containing class that can be disposed safely by allowing the timer
/// callback that it must exit/cancel its processes
/// </summary>
class TimerOwner : IDisposable
{
const int dueTime = 5 * 100; //halve a second
const int timerPeriod = 1 * 1000; //Repeat timer every one second (make it Timeout.Inifinite if no repeating required)
private TimerCanceller timerCanceller = new TimerCanceller();
private Timer timer;
public TimerOwner()
{
timerInit(dueTime);
}
byte[] dummy = new byte[100000];
/// <summary>
///
/// </summary>
/// <param name="dueTime">Pass dueTime for the first time, then TimerPeriod will be passed automatically</param>
private void timerInit(int dueTime)
{
timer = new Timer(timerCallback,
timerCanceller, //this is the trick, it will be kept in the heap until it is consumed by the callback
dueTime,
Timeout.Infinite
);
}
private void timerCallback(object state)
{
try
{
//First exit if the timer was stoped before calling callback. This info is saved in state
var canceller = (TimerCanceller)state;
if (canceller.Cancelled)
{
return; //
}
//Your logic goes here. Please take care ! the callback might have already been called before stoping the timer
//and we might be already here after intending of stoping the timer. In most cases it is fine but try not to consume
//an object of this class because it might be already disposed. If you have to do that, hopefully it will be catched by
//the ObjectDisposedException below
dummy[1] = 50; //just messing up with the object after it might be disposed/nulled
//Yes, we need to check again. Read above note
if (canceller.Cancelled)
{
//Dispose any resource that might have been initialized above
return; //
}
if (timerPeriod != Timeout.Infinite)
{
timerInit(timerPeriod);
}
}
catch (ObjectDisposedException ex)
{
Console.WriteLine("A disposed object accessed");
}
catch (NullReferenceException ex)
{
Console.WriteLine("A nulled object accessed");
}
catch (Exception ex)
{
}
}
public void releaseTimer()
{
timerCanceller.Cancelled = true;
timer.Change(Timeout.Infinite, Timeout.Infinite);
timer.Dispose();
}
public void Dispose()
{
releaseTimer();
dummy = null; //for testing
GC.SuppressFinalize(this);
}
}
class TimerCanceller
{
public bool Cancelled = false;
}
/// <summary>
/// Testing the implementation
/// </summary>
class Program
{
static void Main(string[] args)
{
var list = new System.Collections.Generic.List<TimerOwner>();
Console.WriteLine("Started initializing");
for (int i = 0; i < 500000; i++)
{
list.Add(new TimerOwner());
}
Console.WriteLine("Started releasing");
foreach (var item in list)
{
item.Dispose();
}
Console.WriteLine("Press any key to exit");
Console.ReadKey();
}
}
}
I have attempted to create a derived class of Timer that allows for a 'Pause' latch to be set to keep the worker thread from reactivating the timer. However, Elapsed events are continued to be raised when AutoReset is set to false and the Enabled accessor appears to be doing it's job in preventing the Enabled property of the base class from being modified once the Paused variable is set.
Why is this happening or what strategies should I use to further understand what interactions are actually happening here?
I have attached the implementation of the derived class below.
using System.Timers
class PauseableTimer : Timer
{
public bool Paused;
new public bool Enabled
{
get
{
return base.Enabled;
}
set
{
if (Paused)
{
if (!value) base.Enabled = false;
}
else
{
base.Enabled = value;
}
}
}
}
Example illustrating problem.
class Program
{
private static PauseableTimer _pauseableTimer;
private static int _elapsedCount;
static void Main(string[] args)
{
_pauseableTimer = new PauseableTimer(){AutoReset = false,Enabled = false,Paused = false};
_pauseableTimer.Elapsed += pauseableTimer_Elapsed;
_pauseableTimer.Interval = 1;
_pauseableTimer.Enabled = true;
while(_elapsedCount<100)
{
if (_elapsedCount > 50) _pauseableTimer.Paused = true;
}
}
static void pauseableTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
Console.WriteLine(String.Format("this.Enabled:'{0}',Paused:'{1}',AutoReset:'{2}",_pauseableTimer.Enabled,_pauseableTimer.Paused,_pauseableTimer.AutoReset));
_elapsedCount++;
_pauseableTimer.Interval = _pauseableTimer.Interval == 1 ? 2 : 1; //This line breaks it.
_pauseableTimer.Enabled = true;
}
}
Relevant document, System.Timers.Timer.Interval
Note
If Enabled and AutoReset are both set to false, and the timer has previously been enabled, setting the Interval property causes the Elapsed event to be raised once, as if the Enabled property had been set to true. To set the interval without raising the event, you can temporarily set the AutoReset property to true.
The recommended solution of setting AutoReset to true does not solve the problem because there is an undocumented behavior of setting AutoReset to true during an event handler also allowing for an event to be fired.
The solution seems to be to build out the derived object to the point where you can keep any of the apparently many ways that an event can be fired again from happening.
Below is the implementation that I ended with.
public class PauseableTimer : Timer
{
private bool _paused;
public bool Paused
{
get { return _paused; }
set
{
Interval = _interval;
_paused = value;
}
}
new public bool Enabled
{
get
{
return base.Enabled;
}
set
{
if (Paused)
{
if (!value) base.Enabled = false;
}
else
{
base.Enabled = value;
}
}
}
private double _interval;
new public double Interval
{
get { return base.Interval; }
set
{
_interval = value;
if (Paused){return;}
if (value>0){base.Interval = _interval;}
}
}
public PauseableTimer():base(1){}
public PauseableTimer(double interval):base(interval){}
}
Everything is more complex in multithreading, I'm afraid. Assuming your code is working as you wish, there is a window where in-flight events can get raised after you reset the Enabled property. See this quote from the MSDN docs.
The signal to raise the Elapsed event
is always queued for execution on a
ThreadPool thread. This might result
in the Elapsed event being raised
after the Enabled property is set to
false. The code example for the Stop
method shows one way to work around
this race condition.
Another option is to suppress the event??? I can't explain what is going but the theory presented below should allow you to circumvent this little problem you have discussed. As Steve mentioned put a 'Watch and break point on the enabled property' that you are try set and make sure it is actually being set.
How would I tackle this:
Catch and check for the 'Enabled' property and remove '-=' the subscribing method (handler) as of when needed and then re-add '+=' it again when you do need handle the 'Elapsed' event.
I have used this style quite a few times on a few different WinForms project. If you don't want the 'Elapsed' event to be handled programmatically create a check for and remove it when a certain condition is met and then add it when the opposite condition is met.
if (paused) // determine pause logic to be true in here
{
timer.Elapsed -= ... // remove the handling method.
}
else
{
timer.Elapsed += ... // re-add it in again
}
The above code logic will allow you code to ignore the 'Elapsed' event ever time it is raised whilst the 'Paused' flag is true. I hope the above helps
In System.Timers.Timer the Elapsed event is added to the ThreadPool when the class is created. After that it is fired. The Enabled property can be false at that time. You can't do anything about that, but what you can do is test if the Enabled property is true when the Elapsed event fires. I do override the Enabled property to make this magic happening, as extra I also put an IsDisposed property in it:
public class DisposableTimer : System.Timers.Timer {
/// <summary>
/// override the Timer base class Enabled property
/// </summary>
/// <remarks>
/// the code in the Elapsed event should only be executed when the Enabled property is set to "true".
/// we cannot prevent that the Elapsed event is fired at the start, because its automatically put in the ThreadPool,
/// but we can prevent that the code in it can be executed when the Enabled property is "false".
/// </remarks>
private bool enabled;
public new bool Enabled
{
get
{
return enabled;
}
set
{
enabled = base.Enabled = value;
}
}
/// <summary>
/// count the heartbeats
/// </summary>
public int HeartbeatCounter { get; set; }
/// <summary>
/// name of timer
/// </summary>
public string TimerName { get; set; }
/// <summary>
/// show heartbeat on console
/// </summary>
public bool ShowHeartBeat { get; set; }
// type of entry in eventlog
public EventLogEntryType EventLogEntryType { get; set; }
// updated interval to process messages
public Func<double> UpdatebleInterval { get; set; }
/// <summary>
/// used eventlog
/// </summary>
public EventLog EventLog { get; set; }
/// <summary>
/// message logging
/// </summary>
/// <remarks>
/// this property needs to be dynamic because in
/// pda service a different class is used but luckily :-)
/// with the same method for adding loggings.
/// </remarks>
public dynamic MessageLogging { get; set; }
/// <summary>
/// make sure there are no overlapping set of timer callbacks
/// </summary>
private object locker;
/// <summary>
/// initialize timer class
/// </summary>
/// <param name="actions">action to perform</param>
/// <param name="timerName">name of timer</param>
public DisposableTimer(List<Action> actions, string timerName) : base()
{
// used to make sure there are no overlapping executing sets of timer callbacks
locker = new object();
// wrapper for the actions that need to be performed.
base.Elapsed += (s, a) => Callback(actions);
// set name of timer
this.TimerName = timerName;
/*
* only once a callback is executed after elapsed time,
* because there is only one callback executed there can be
* no overlap, because the "reset" is done after the set of
* callbacks are executed.
*/
AutoReset = false;
// timer is not started yet
Enabled = false;
}
/// <summary>
/// check if verwijder bericht timer is disposed
/// </summary>
public bool IsDisposed
{
get
{
var timerType = typeof(System.Timers.Timer);
var timerDisposedField = timerType.GetField("disposed", BindingFlags.NonPublic | BindingFlags.Instance);
return (bool)timerDisposedField.GetValue(this);
}
}
/// <summary>
/// after a callback a timer needs to be reset to continue running if AutoReset=false.
/// </summary>
/// <param name="interval">new interval of timer</param>
private void Reset(double interval)
{
// stop the timer
Stop();
// only do when not disposed yet.
if (!IsDisposed)
{
// adjust interval if needed
if (interval != 0)
Interval = interval;
// release exclusive lock
Monitor.Exit(locker);
}
// start the timer again
Start();
}
/// <summary>
/// only start if not disposed and started yet
/// </summary>
public new void Start()
{
if (!IsDisposed && !Enabled)
Enabled = true;
}
/// <summary>
/// only stop if not disposed and stopped yet
/// </summary>
public new void Stop()
{
if (!IsDisposed && Enabled)
Enabled = false;
}
/// <summary>
/// set of callbacks to perform after timer elapse interval
/// </summary>
/// <param name="callBackActions">list of callbacks inside this wrapper to execute</param>
public void Callback(List<Action> callBackActions)
{
// only execute callbacks if timer is enabled.
if (Enabled)
{
/*
* AutoReset = false, so a callback is only executed once,
* because of this overlapping callbacks should not occur,
* but to be sure exclusive locking is also used.
*/
var hasLock = false;
// show heartbeat at output window
if (ShowHeartBeat)
Debug.WriteLine(string.Format("HeartBeat interval: {0}...{1}/thread: 0x{2:X4}", TimerName, ++HeartbeatCounter, AppDomain.GetCurrentThreadId() ));
// execute callback action.
try
{
// only perform set of actions if not executing already on this thread.
Monitor.TryEnter(locker, ref hasLock);
if (hasLock)
{
// show heartbeat at output window
if (ShowHeartBeat)
Debug.WriteLine(string.Format(" action: {0}...{1}/thread: 0x{2:X4}", TimerName, HeartbeatCounter, AppDomain.GetCurrentThreadId()));
// execute the set of callback actions
foreach (Action callBackAction in callBackActions)
{
// execute callback
try
{
callBackAction();
}
// log error, but keep the action loop going.
catch (Exception ex)
{
EventLog.WriteEntry(ex.Message, EventLogEntryType.Warning);
MessageLogging.Insert(ex.Message);
}
}
}
// show that action is busy
else if (ShowHeartBeat)
Debug.WriteLine(string.Format(" busy: {0}...{1}/thread: 0x{2:X4}", TimerName, HeartbeatCounter, AppDomain.GetCurrentThreadId()));
}
// adjust interval when needed and release exclusive lock when done.
finally
{
// after the complete action is finished the lock should be released.
if (hasLock)
{
// timer interval can be changed when timer is active, callback function is needed for this.
double newInterval = 0;
if (UpdatebleInterval != null)
{
// calculate new interval for timer
double updatedInterval = UpdatebleInterval();
if (Interval != updatedInterval)
{
// based on Dutch
var dutchCultureInfo = new CultureInfo("nl-NL", false).TextInfo;
// write interval change to loggings
string intervalMessage = dutchCultureInfo.ToTitleCase(string.Format(#"{0} interval veranderd van {1} naar {2} seconden", TimerName, Interval / 1000, updatedInterval / 1000));
EventLog.WriteEntry(intervalMessage, EventLogEntryType.Information);
MessageLogging.Insert(intervalMessage);
// set for new interval
newInterval = updatedInterval;
}
}
// make ready for new callback after elapsed time, lock can be released by now.
Reset(newInterval);
}
}
}
// show heartbeat at output window
else if (ShowHeartBeat)
Debug.WriteLine(string.Format("HeartBeat thread: {0}...{1}/thread: 0x{2:X4}", TimerName, ++HeartbeatCounter, AppDomain.GetCurrentThreadId()));
}
}
I would reformat your code:
// from this
if (!value) base.Enabled = false;
// to this
if (!value)
base.Enabled = false;
Not only does it read better, you can put a break point on the key line and see if it's being executed
I need to design perfect worker thread method. The method must do the following:
1) extract something from queue (let's say a queue of string) and do something
2) stop and return when class is disposed
3) wait for some event (that queue is not empty) and do not consume cpu
4) run in separate thread
Main thread will add string to queue and signal thread method to continue and do the job.
I would like you to provide me the the template with required syncronization objects.
class MyClass, IDisposable
{
// Thread safe queue from third party
private ThreadSafeQueue<string> _workerQueue;
private Thread _workerThread;
public bool Initialize()
{
_workerThread = new Thread(WorkerThread).Start();
}
public AddTask(string object)
{
_workerQueue.Enqueue(object);
// now we must signal worker thread
}
// this is worker thread
private void WorkerThread()
{
// This is what worker thread must do
List<string> objectList = _workerQueue.EnqueAll
// Do something
}
// Yeap, this is Dispose
public bool Dispose()
{
}
}
Try something like this. instantiate with type string and give it a delegate to process your string:
public class SuperQueue<T> : IDisposable where T : class
{
readonly object _locker = new object();
readonly List<Thread> _workers;
readonly Queue<T> _taskQueue = new Queue<T>();
readonly Action<T> _dequeueAction;
/// <summary>
/// Initializes a new instance of the <see cref="SuperQueue{T}"/> class.
/// </summary>
/// <param name="workerCount">The worker count.</param>
/// <param name="dequeueAction">The dequeue action.</param>
public SuperQueue(int workerCount, Action<T> dequeueAction)
{
_dequeueAction = dequeueAction;
_workers = new List<Thread>(workerCount);
// Create and start a separate thread for each worker
for (int i = 0; i < workerCount; i++)
{
Thread t = new Thread(Consume) { IsBackground = true, Name = string.Format("SuperQueue worker {0}",i )};
_workers.Add(t);
t.Start();
}
}
/// <summary>
/// Enqueues the task.
/// </summary>
/// <param name="task">The task.</param>
public void EnqueueTask(T task)
{
lock (_locker)
{
_taskQueue.Enqueue(task);
Monitor.PulseAll(_locker);
}
}
/// <summary>
/// Consumes this instance.
/// </summary>
void Consume()
{
while (true)
{
T item;
lock (_locker)
{
while (_taskQueue.Count == 0) Monitor.Wait(_locker);
item = _taskQueue.Dequeue();
}
if (item == null) return;
// run actual method
_dequeueAction(item);
}
}
/// <summary>
/// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
/// </summary>
public void Dispose()
{
// Enqueue one null task per worker to make each exit.
_workers.ForEach(thread => EnqueueTask(null));
_workers.ForEach(thread => thread.Join());
}
}
What you are describing is best accomplished with the producer-consumer pattern. This pattern is most easily implemented with a blocking queue. If you are using .NET 4.0 then you can take advantage of the BlockingCollection class. Here is how I am seeing your code working. In the following example I am using a null value as sentinel for gracefully ending the consumer, but you could also take advantage of the CancellationToken parameter on the Take method.
public class MyClass : IDisposable
{
private BlockingCollection<string> m_Queue = new BlockingCollection<string>();
public class MyClass()
{
var thread = new Thread(Process);
thread.IsBackground = true;
thread.Start();
}
public void Dispose()
{
m_Queue.Add(null);
}
public void AddTask(string item)
{
if (item == null)
{
throw new ArgumentNullException();
}
m_Queue.Add(item);
}
private void Process()
{
while (true)
{
string item = m_Queue.Take();
if (item == null)
{
break; // Gracefully end the consumer thread.
}
else
{
// Process the item here.
}
}
}
}
I think you should consider using BackgroundWorker class, which may fit well to your needs.
Sounds like BlockingQueue is what you need.
You should take a look at the new .Net 4 System.Collections.Concurrent Namespace. Also this little example should help you to get a better understanding on how to use it.