How to ensure timer is fully paused? - c#

Assume we have this event attached to the timer event handler.
private void TimerTick(object sender, ElapsedEventArgs e)
{
if(_gaurd) return;
lock (this) // lock per instance
{
_gaurd = true;
if (!_timer.Enabled) return;
OnTick(); // somewhere inside here timer may pause it self.
_gaurd = false;
}
}
Now there two things that can pause this timer. One is user request from UI thread, second is the timer which may pause it self.
If the timer pause it self we can guarantee the pause will complete before we continue.
timer.Stop();
OnPause(); // timer must be paused because OnPause() is not thread safe.
But if the user, requests for timer pause the request is from another thread and we can not guarantee timer is fully paused or not.
timer.Stop();
OnPause(); // timer event may be still inside OnTick() and may conflict with OnPause()
-------------------------------------------------------------------------------------------------------
So I'm looking for a way to make this thread safe. This is what I have tried so far but I'm not sure if this works in all situations or not.
Its looking good but want to make sure that if there is anything I'm not aware of. or maybe to know if there are better ways to make this process thread safe.
I have tried to separate user request from Inner workings of timer. therefore I have two Pause methods for my timer.
public class Timer
{
internal void InternalStop() // must be called by timer itself.
{
timer.Pause(); // causes no problem
}
public void Stop() // user request must come here. (if timer call this deadlock happens)
{
InternalStop();
lock (this) // reference of timer
{
// do nothing and wait for OnTick().
}
}
}
This is not actual code but behavior is same. it should illustrate that this class is not thread safe. :
public class WorkingArea
{
private List<Worker> _workers;
public void OnTick()
{
foreach(var worker in _workers)
{
worker.Start();
}
if(_workers.TrueForAll(w => w.Ends))
{
PauseTimer();
}
}
public void OnPause() // after timer paused
{
foreach(var Worker in _workers)
{
worker.Stop();
}
}
}

My timer was already thread safe.
it was all about the fact that I didn't know about Re-entrant locks
So if user from another thread request to pause timer , lock will work just fine and will block until timer is fully paused.
If the timer internally pauses it self it wont deal lock. because its in the same thread the lock was acquired.
public class Timer
{
private timer = new System.Timers.Timer();
private bool _guard = false;
// stops the timer and waits until OnTick returns and lock releases.
// timer can safely pause it self within OnTick.
// if user request to pause from another thread, full pause is ensured
public void Stop()
{
timer.Pause();
lock (this) // reference of timer. it wont dead lock
{
// do nothing and wait for OnTick().
}
}
private void TimerTick(object sender, ElapsedEventArgs e)
{
if(_gaurd) return;
lock (this) // lock per instance
{
_gaurd = true;
if (!_timer.Enabled) return;
OnTick(); // somewhere inside here timer may pause it self.
_gaurd = false;
}
}
}

Related

how to pause/resume a thread

How can I pause/resume a thread? Once I Join() a thread, I can't restart it.
So how can I start a thread and make it pause whenever the button 'pause' is pressed, and resume it when resume button is pressed?
The only thing this thread does, is show some random text in a label control.
Maybe the ManualResetEvent is a good choice.
A short example:
private static EventWaitHandle waitHandle = new ManualResetEvent(initialState: true);
// Main thread
public void OnPauseClick(...) {
waitHandle.Reset();
}
public void OnResumeClick(...) {
waitHandle.Set();
}
// Worker thread
public void DoSth() {
while (true) {
// show some random text in a label control (btw. you have to
// dispatch the action onto the main thread)
waitHandle.WaitOne(); // waits for the signal to be set
}
}
I could suggest you to read Threading in C#, by Joe Albahari, particularly Suspend and Resume section:
A thread can be explicitly suspended and resumed via the deprecated methods Thread.Suspend and Thread.Resume. This mechanism is completely separate to that of blocking. Both systems are independent and operate in parallel.
A thread can suspend itself or another thread. Calling Suspend results in the thread briefly entering the SuspendRequested state, then upon reaching a point safe for garbage collection, it enters the Suspended state. From there, it can be resumed only via another thread that calls its Resume method. Resume will work only on a suspended thread, not a blocked thread.
From .NET 2.0, Suspend and Resume have been deprecated, their use discouraged because of the danger inherent in arbitrarily suspending another thread. If a thread holding a lock on a critical resource is suspended, the whole application (or computer) can deadlock. This is far more dangerous than calling Abort — which results in any such locks being released (at least theoretically) by virtue of code in finally blocks.
It's not the best idea to manually suspend and resume threads. However, you can easily simulate this behavior by using thread synchronization primitives (like ManualResetEvent)
Take a look at this question, you may find it helpful.
But I believe you can easily achieve your goal of 'showing random text in a label control' on a time basis by using timers.
Here is a quick example using DispatcherTimer
var timer = new DispatcherTimer();
timer.Tick += (s, e) => Label.Text = GetRandomText();
timer.Interval = TimeSpan.FromMilliseconds(500);
timer.Start();
You can pause it by calling timer.Stop() and then timer.Start() again to resume.
Here's two ways that's worked for me. Both assume that the worker thread has it's own processing loop.
Have the thread invoke a callback to request permission to keep going
Have the parent invoke a method on the thread's class to signal it
The console application example below shows both approaches, using a callback to pause/continue, and a worker method to stop. Another advantage of the callback method is that it's also convenient for passing back status updates while it's checking for permission to continue.
using System;
using System.Threading;
namespace ConsoleApplication7
{
class Program
{
static bool keepGoing;
static void Main(string[] args)
{
keepGoing = true;
Worker worker = new Worker(new KeepGoingDelegate(KeepGoing));
Thread thread = new Thread(worker.DoWork);
thread.IsBackground = true;
thread.Start();
while (thread.ThreadState != ThreadState.Stopped)
{
switch (Console.ReadKey(true).KeyChar)
{
case 'p':
keepGoing = false;
break;
case 'w':
keepGoing = true;
break;
case 's':
worker.Stop();
break;
}
Thread.Sleep(100);
}
Console.WriteLine("Done");
Console.ReadKey();
}
static bool KeepGoing()
{
return keepGoing;
}
}
public delegate bool KeepGoingDelegate();
public class Worker
{
bool stop = false;
KeepGoingDelegate KeepGoingCallback;
public Worker(KeepGoingDelegate callbackArg)
{
KeepGoingCallback = callbackArg;
}
public void DoWork()
{
while (!stop)
{
Console.Write(KeepGoingCallback()?"\rWorking":"\rPaused ");
Thread.Sleep(100);
}
Console.WriteLine("\nStopped");
}
public void Stop()
{
stop = true;
}
}
}

Reliably stop System.Threading.Timer?

Well I've searched a lot for a solution to this. I'm looking for a clean and simple way to prevent the callback method of a System.Threading.Timer from being invoked after I've stopped it.
I can't seem to find any, and this has led me, on occassion, to resort to the dreaded thread-thread.sleep-thread.abort combo.
Can it be done using lock?
An easier solution might to be to set the Timer never to resume; the method Timer.Change can take values for dueTime and period that instruct the timer never to restart:
this.Timer.Change(Timeout.Infinite, Timeout.Infinite);
Whilst changing to use System.Timers.Timer might be a "better" solution, there are always going to be times when that's not practical; just using Timeout.Infinite should suffice.
like Conrad Frix suggested you should use the System.Timers.Timer class instead, like:
private System.Timers.Timer _timer = new System.Timers.Timer();
private volatile bool _requestStop = false;
public constructor()
{
_timer.Interval = 100;
_timer.Elapsed += OnTimerElapsed;
_timer.AutoReset = false;
_timer.Start();
}
private void OnTimerElapsed(object sender, System.Timers.ElapsedEventArgs e)
{
// do work....
if (!_requestStop)
{
_timer.Start();//restart the timer
}
}
private void Stop()
{
_requestStop = true;
_timer.Stop();
}
private void Start()
{
_requestStop = false;
_timer.Start();
}
The MSDN Docs suggest that you use the Dispose(WaitHandle) method to stop the timer + be informed when callbacks will no longer be invoked.
For the System.Threading.Timer one can do the following (Will also protect the callback-method from working on a disposed timer - ObjectDisposedException):
class TimerHelper : IDisposable
{
private System.Threading.Timer _timer;
private readonly object _threadLock = new object();
public event Action<Timer,object> TimerEvent;
public void Start(TimeSpan timerInterval, bool triggerAtStart = false,
object state = null)
{
Stop();
_timer = new System.Threading.Timer(Timer_Elapsed, state,
System.Threading.Timeout.Infinite, System.Threading.Timeout.Infinite);
if (triggerAtStart)
{
_timer.Change(TimeSpan.FromTicks(0), timerInterval);
}
else
{
_timer.Change(timerInterval, timerInterval);
}
}
public void Stop(TimeSpan timeout = TimeSpan.FromMinutes(2))
{
// Wait for timer queue to be emptied, before we continue
// (Timer threads should have left the callback method given)
// - http://woowaabob.blogspot.dk/2010/05/properly-disposing-systemthreadingtimer.html
// - http://blogs.msdn.com/b/danielvl/archive/2011/02/18/disposing-system-threading-timer.aspx
lock (_threadLock)
{
if (_timer != null)
{
ManualResetEvent waitHandle = new ManualResetEvent(false)
if (_timer.Dispose(waitHandle))
{
// Timer has not been disposed by someone else
if (!waitHandle.WaitOne(timeout))
throw new TimeoutException("Timeout waiting for timer to stop");
}
waitHandle.Close(); // Only close if Dispose has completed succesful
_timer = null;
}
}
}
public void Dispose()
{
Stop();
TimerEvent = null;
}
void Timer_Elapsed(object state)
{
// Ensure that we don't have multiple timers active at the same time
// - Also prevents ObjectDisposedException when using Timer-object
// inside this method
// - Maybe consider to use _timer.Change(interval, Timeout.Infinite)
// (AutoReset = false)
if (Monitor.TryEnter(_threadLock))
{
try
{
if (_timer==null)
return;
Action<Timer, object> timerEvent = TimerEvent;
if (timerEvent != null)
{
timerEvent(_timer, state);
}
}
finally
{
Monitor.Exit(_threadLock);
}
}
}
}
This is how one can use it:
void StartTimer()
{
TimerHelper _timerHelper = new TimerHelper();
_timerHelper.TimerEvent += (timer,state) => Timer_Elapsed();
_timerHelper.Start(TimeSpan.FromSeconds(5));
System.Threading.Sleep(TimeSpan.FromSeconds(12));
_timerHelper.Stop();
}
void Timer_Elapsed()
{
// Do what you want to do
}
For what it's worth, we use this pattern quite a bit:
// set up timer
Timer timer = new Timer(...);
...
// stop timer
timer.Dispose();
timer = null;
...
// timer callback
{
if (timer != null)
{
..
}
}
This answer relates to System.Threading.Timer
I've read a lot of nonsense about how to synchronize disposal of System.Threading.Timer all over the net. So that's why I'm posting this in an attempt to rectify the situation somewhat. Feel free to tell me off / call me out if something I'm writing is wrong ;-)
Pitfalls
In my opinion there's these pitfalls:
Timer.Dispose(WaitHandle) can return false. It does so in case it's already been disposed (I had to look at the source code). In that case it won't set the WaitHandle - so don't wait on it!
not handling a WaitHandle timeout. Seriously - what are you waiting for in case you're not interested in a timeout?
Concurrency issue as mentioned here on msdn where an ObjectDisposedException can occur during (not after) disposal.
Timer.Dispose(WaitHandle) does not work properly with -Slim waithandles, or not as one would expect. For example, the following does not work (it blocks forever):
using(var manualResetEventSlim = new ManualResetEventSlim)
{
timer.Dispose(manualResetEventSlim.WaitHandle);
manualResetEventSlim.Wait();
}
Solution
Well the title is a bit "bold" i guess, but below is my attempt to deal with the issue - a wrapper which handles double-disposal, timeouts, and ObjectDisposedException. It does not provide all of the methods on Timer though - but feel free to add them.
internal class Timer
{
private readonly TimeSpan _disposalTimeout;
private readonly System.Threading.Timer _timer;
private bool _disposeEnded;
public Timer(TimeSpan disposalTimeout)
{
_disposalTimeout = disposalTimeout;
_timer = new System.Threading.Timer(HandleTimerElapsed);
}
public event Action Elapsed;
public void TriggerOnceIn(TimeSpan time)
{
try
{
_timer.Change(time, Timeout.InfiniteTimeSpan);
}
catch (ObjectDisposedException)
{
// race condition with Dispose can cause trigger to be called when underlying
// timer is being disposed - and a change will fail in this case.
// see
// https://msdn.microsoft.com/en-us/library/b97tkt95(v=vs.110).aspx#Anchor_2
if (_disposeEnded)
{
// we still want to throw the exception in case someone really tries
// to change the timer after disposal has finished
// of course there's a slight race condition here where we might not
// throw even though disposal is already done.
// since the offending code would most likely already be "failing"
// unreliably i personally can live with increasing the
// "unreliable failure" time-window slightly
throw;
}
}
}
private void HandleTimerElapsed(object state)
{
Elapsed?.Invoke();
}
public void Dispose()
{
var waitHandle = new ManualResetEvent(false));
// returns false on second dispose
if (_timer.Dispose(waitHandle))
{
if (waitHandle.WaitOne(_disposalTimeout))
{
_disposeEnded = true;
waitHandle.Dispose();
}
else
{
// don't dispose the wait handle, because the timer might still use it.
// Disposing it might cause an ObjectDisposedException on
// the timer thread - whereas not disposing it will
// result in the GC cleaning up the resources later
throw new TimeoutException(
"Timeout waiting for timer to stop. (...)");
}
}
}
}
You can't guarantee that your code that supposed to stop the timer will execute before timer event invocation.
For example, suppose on time moment 0 you initialized timer to call event when time moment 5 comes. Then on time moment 3 you decided that you no longer needed the call. And called method you want to write here. Then while method was JIT-ted comes time moment 4 and OS decides that your thread exhaust its time slice and switch. And timer will invoke the event no matter how you try - your code just won't have a chance to run in worst case scenario.
That's why it is safer to provide some logic in the event handler. Maybe some ManualResetEvent that will be Reset as soon as you no longer needed event invocation. So you Dispose the timer, and then set the ManualResetEvent. And in the timer event handler first thing you do is test ManualResetEvent. If it is in reset state - just return immediately. Thus you can effectively guard against undesired execution of some code.
To me, this seems to be the correct way to go:
Just call dispose when you are done with the timer. That will stop the timer and prevent future scheduled calls.
See example below.
class Program
{
static void Main(string[] args)
{
WriteOneEverySecond w = new WriteOneEverySecond();
w.ScheduleInBackground();
Console.ReadKey();
w.StopTimer();
Console.ReadKey();
}
}
class WriteOneEverySecond
{
private Timer myTimer;
public void StopTimer()
{
myTimer.Dispose();
myTimer = null;
}
public void ScheduleInBackground()
{
myTimer = new Timer(RunJob, null, 1000, 1000);
}
public void RunJob(object state)
{
Console.WriteLine("Timer Fired at: " + DateTime.Now);
}
}
Perhaps you should do the opposite. Use system.timers.timer, set the AutoReset to false and only Start it when you want to
You can stop a timer by creating a class like this and calling it from, for example, your callback method:
public class InvalidWaitHandle : WaitHandle
{
public IntPtr Handle
{
get { return InvalidHandle; }
set { throw new InvalidOperationException(); }
}
}
Instantiating timer:
_t = new Timer(DisplayTimerCallback, TBlockTimerDisplay, 0, 1000);
Then inside callback method:
if (_secondsElapsed > 80)
{
_t.Dispose(new InvalidWaitHandle());
}
There is a MSDN link how to achieve stop timer correctly. Use ControlThreadProc() method with HandleElapsed(object sender, ElapsedEventArgs e) event synchronized by syncPoint static class variable. Comment out Thread.Sleep(testRunsFor); on ControlThreadProc() if it is not suitable(probably).
The key is there that using static variable and an atomic operation like Interlocked.CompareExchange on conditional statements.
Link :
Timer.Stop Method

Single threaded timer

I wanted a timer with the following properties:
No matter how many times start is called, only one call back thread is ever running
The time spent in the call back function was ignored with regards to the interval. E.g if the interval is 100ms and the call back takes 4000ms to execute, the callback is called at 100ms, 4100ms etc.
I couldn't see anything available so wrote the following code. Is there a better way to do this?
/**
* Will ensure that only one thread is ever in the callback
*/
public class SingleThreadedTimer : Timer
{
protected static readonly object InstanceLock = new object();
//used to check whether timer has been disposed while in call back
protected bool running = false;
virtual new public void Start()
{
lock (InstanceLock)
{
this.AutoReset = false;
this.Elapsed -= new ElapsedEventHandler(SingleThreadedTimer_Elapsed);
this.Elapsed += new ElapsedEventHandler(SingleThreadedTimer_Elapsed);
this.running = true;
base.Start();
}
}
virtual public void SingleThreadedTimer_Elapsed(object sender, ElapsedEventArgs e)
{
lock (InstanceLock)
{
DoSomethingCool();
//check if stopped while we were waiting for the lock,
//we don't want to restart if this is the case..
if (running)
{
this.Start();
}
}
}
virtual new public void Stop()
{
lock (InstanceLock)
{
running = false;
base.Stop();
}
}
}
Here's a quick example I just knocked up;
using System.Threading;
//...
public class TimerExample
{
private System.Threading.Timer m_objTimer;
private bool m_blnStarted;
private readonly int m_intTickMs = 1000;
private object m_objLockObject = new object();
public TimerExample()
{
//Create your timer object, but don't start anything yet
m_objTimer = new System.Threading.Timer(callback, m_objTimer, Timeout.Infinite, Timeout.Infinite);
}
public void Start()
{
if (!m_blnStarted)
{
lock (m_objLockObject)
{
if (!m_blnStarted) //double check after lock to be thread safe
{
m_blnStarted = true;
//Make it start in 'm_intTickMs' milliseconds,
//but don't auto callback when it's done (Timeout.Infinite)
m_objTimer.Change(m_intTickMs, Timeout.Infinite);
}
}
}
}
public void Stop()
{
lock (m_objLockObject)
{
m_blnStarted = false;
}
}
private void callback(object state)
{
System.Diagnostics.Debug.WriteLine("callback invoked");
//TODO: your code here
Thread.Sleep(4000);
//When your code has finished running, wait 'm_intTickMs' milliseconds
//and call the callback method again,
//but don't auto callback (Timeout.Infinite)
m_objTimer.Change(m_intTickMs, Timeout.Infinite);
}
}
The .NET Framework provides four timers. Two of these are general-purpose multithreaded
timers:
System.Threading.Timer
System.Timers.Timer
The other two are special-purpose single-threaded timers:
System.Windows.Forms.Timer (Windows Forms timer)
System.Windows.Threading.DispatcherTimer (WPF timer)
The last 2 are designed to eliminate thread-safety issues for WPF and Windows Forms applications.
For example, using WebBrowser inside a timer to capture screenshots from webpage needs to be single-threaded and gives an error at runtime if it is on another thread.
The single-thread timers have the following benefits
You can forget about thread safety.
A fresh Tick will never fire until the previous Tick has finished
processing.
You can update user interface elements and controls directly from
Tick event handling code, without calling Control.BeginInvoke or
Dispatcher.BeginIn voke.
and main disadvantage to note
One thread serves all timers—as well as the processing UI events.
Which means that the Tick event handler must execute quickly,
otherwise the user interface becomes unresponsive.
source: most are scraps from C# in a Nutshell book -> Chapter 22 -> Advanced threading -> Timers -> Single-Threaded Timers
For anyone who needs a single thread timer and wants the timer start to tick after task done.
System.Timers.Timer could do the trick without locking or [ThreadStatic]
System.Timers.Timer tmr;
void InitTimer(){
tmr = new System.Timers.Timer();
tmr.Interval = 300;
tmr.AutoReset = false;
tmr.Elapsed += OnElapsed;
}
void OnElapsed( object sender, System.Timers.ElapsedEventArgs e )
{
backgroundWorking();
// let timer start ticking
tmr.Enabled = true;
}
Credit to Alan N
source https://www.codeproject.com/Answers/405715/System-Timers-Timer-single-threaded-usage#answer2
Edit: spacing
Look at the [ThreadStatic] attribute and the .Net 4.0 ThreadLocal generic type. This will probably quickly give you a way to code this without messing with thread locking etc.
You could have a stack inside your time class, and you could implement a Monitor() method that returns a IDisposable, so you can use the timer like so:
using (_threadTimer.Monitor())
{
// do stuff
}
Have the timer-monitor pop the the interval timestamp off the stack during Dispose().
Manually coding all the locking and thread recognition is an option as has been mentioned. However, locking will influence the time used, most likely more than having to initialize an instance per thread using ThreadLocal
If you're interested, I might knock up an example later
Here is a simple PeriodicNonOverlappingTimer class, that provides just the requested features, and nothing more than that. This timer cannot be started and stopped on demand, and neither can have its interval changed. It just invokes the specified action periodically in a non overlapping manner, until the timer is disposed.
/// <summary>
/// Invokes an action on the ThreadPool at specified intervals, ensuring
/// that the invocations will not overlap, until the timer is disposed.
/// </summary>
public class PeriodicNonOverlappingTimer : IDisposable, IAsyncDisposable
{
private readonly System.Threading.Timer _timer;
public PeriodicNonOverlappingTimer(Action periodicAction,
TimeSpan dueTime, TimeSpan period)
{
// Arguments validation omitted
_timer = new(_ =>
{
var stopwatch = Stopwatch.StartNew();
periodicAction();
var nextDueTime = period - stopwatch.Elapsed;
if (nextDueTime < TimeSpan.Zero) nextDueTime = TimeSpan.Zero;
try { _timer.Change(nextDueTime, Timeout.InfiniteTimeSpan); }
catch (ObjectDisposedException) { } // Ignore this exception
});
_timer.Change(dueTime, Timeout.InfiniteTimeSpan);
}
public void Dispose() => _timer.DisposeAsync().AsTask().Wait();
public ValueTask DisposeAsync() => _timer.DisposeAsync();
}
Usage example. Shows how to create a non-overlapping timer that starts immediately, with a period of 10 seconds.
var timer = new PeriodicNonOverlappingTimer(() =>
{
DoSomethingCool();
}, TimeSpan.Zero, TimeSpan.FromSeconds(10));
//...
timer.Dispose(); // Stop the timer once and for all
In case the DoSomethingCool fails, the exception will be thrown on the ThreadPool, causing the process to crash. So you may want to add a try/catch block, and handle all the exceptions that may occur.
The Dispose is a potentially blocking method. If the periodicAction is currently running, the Dispose will block until the last invocation is completed.
If you don't want to wait for this to happen, you can do this instead:
_ = timer.DisposeAsync(); // Stop the timer without waiting it to finish

C# killing a thread

In my app, I have a thread that runs continuously. By using Thread.Sleep(), the function executes every 10 minutes.
I need to be able to kill this thread when a user clicks a button. I know Thread.Abort() is not reliable. I can use a variable to stop the thread, but since it is sleeping it could be another 10 minutes before the thread kills itself.
Any ideas?
Why don't you use a timer to schedule the task every ten minutes instead. That will run your code on a thread pool thread and thus you will not have to manage this yourself.
For more details see the System.Threading.Timer class.
Instead of Thread.Sleep use a System.Threading.ManualResetEvent. The WaitOne method has a timeout just like Thread.Sleep, your thread will sleep for that interval unless the event is triggered first, and the return value tells you whether the interval elapsed or the event was set.
So here's a sample that users timers to do the work as suggested by Brian. Use start/stop as needed. To cleanup the (Program) object once you are done with it make sure you call Dispose.
Just note that when you call Stop it will prevent the timer from firing again, however you still may have a worker thread in the middle of executing the timer_Elapsed handler, i.e. stopping the timer doesn't stop any currently executing worker thread.
using System;
using System.Timers;
namespace TimerApp
{
class Program : IDisposable
{
private Timer timer;
public Program()
{
this.timer = new Timer();
this.timer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
this.timer.AutoReset = true;
this.timer.Interval = TimeSpan.FromMinutes(10).TotalMilliseconds;
}
void timer_Elapsed(object sender, ElapsedEventArgs e)
{
// TODO...your periodic processing, executed in a worker thread.
}
static void Main(string[] args)
{
// TODO...your app logic.
}
public void Start()
{
this.timer.Start();
}
public void Stop()
{
this.timer.Stop();
}
public void Dispose()
{
this.timer.Dispose();
}
}
}
Building on Ben's answer, here's the pattern to help you out...
using System.Threading;
public class MyWorker {
private ManualResetEvent mResetEvent = new ManualResetEvent(false);
private volatile bool mIsAlive;
private const int mTimeout = 6000000;
public void Start()
{
if (mIsAlive == false)
{
mIsAlive = true;
Thread thread = new Thread(new ThreadStart(RunThread));
thread.Start();
}
}
public void Stop()
{
mIsAlive = false;
mResetEvent.Set();
}
public void RunThread()
{
while(mIsAlive)
{
//Reset the event -we may be restarting the thread.
mResetEvent.Reset();
DoWork();
//The thread will block on this until either the timeout
//expires or the reset event is signaled.
if (mResetEvent.WaitOne(mTimeout))
{
mIsAlive = false; // Exit the loop.
}
}
}
public void DoWork()
{
//...
} }
One possibility is to not have it sleep for ten minutes. Have it sleep for 10 seconds then only do its work on every sixtieth wakeup. Then you only have a latency of ten seconds before it stops.
Aside: This is not necessarily the best solution but it's probably the quickest to implement. As with all possibilities you should do a cost/benefit analysis when selecting which solution is right for you.
If ten seconds is still too much, you can drop it further although keep in mind that dropping it too far will result in a possible performance impact.
You're right that you shouldn't kill threads from outside, it's usually a recipe for disaster if you happen to do it while they have a lock on some resource that's not freed on kill. Threads should always be responsible for their own resources, including their lifetimes.

How to have a loop in a Windows service without using the Timer

I want to call a Business layer method from a Windows service (done using C# and .NET) after every 10 seconds. However, i dont want to use the Timer_Elapsed event since it starts up another thread/process if the first thread/process is still running. I just need a single threaded approach, since multiple calls to the same Business method creates unwanted complications.
So i added a do--while loop in the on_start. I know this is not the correct way since it spawns this process which becomes an orphan if the service is shut down.
How can i approach this problem ?
Regards,
Chak
There's another way to get timed execution, the WaitHandle.WaitOne() method provides a timeout argument. That works very nicely in a service as it lets you implement the need to stop the service and periodic execution in a single method call. The template looks like this:
Thread Worker;
AutoResetEvent StopRequest = new AutoResetEvent(false);
protected override void OnStart(string[] args) {
// Start the worker thread
Worker = new Thread(DoWork);
Worker.Start();
}
protected override void OnStop() {
// Signal worker to stop and wait until it does
StopRequest.Set();
Worker.Join();
}
private void DoWork(object arg) {
// Worker thread loop
for (;;) {
// Run this code once every 10 seconds or stop right away if the service
// is stopped
if (StopRequest.WaitOne(10000)) return;
// Do work...
//...
}
}
Use a timer, but as soon as you enter the Timer handler method, disable the timer so that no more events are raised. Just before exiting the handler, re-enable the timer.
Check out this discussion, and in particular the answer by jsw. It suggests a synchronization mechanism to prevent multiple simultaneous calls to the business logic. Just disabling the timer in the Elapsed handler method isn't guaranteed to prevent parallel calls since the handler is invoked on a separate thread. Use a lock as jsw suggests, and stop the timer within the synchronized code block.
Alternatively, you could use a Timer and set the AutoReset property to false. That way, the Elapsed event is raised only once and you can reset the timer manually towards the end of the handler method.
while(true)
{
..do something
Thread.sleep( some time or day);
}
Thread thread;
private void DoWork(object arg)
{
while (true)
{
// Run this code once every 20 seconds or stop if the service is stopped
try
{
Thread.Sleep(20000);
//Do work....
}
catch(ThreadInterruptedException)
{
return;
}
}
}
protected override void OnStart(string[] args)
{
// Start the thread
thread = new Thread(DoWork);
mWorker.Start();
}
protected override void OnStop()
{
// interrupt thread and wait until it does
thread.Interrupt();
thread.Join();
}

Categories

Resources