So what do you think is the best way to prevent multiple threads of a C# Windows service running simultaneously (the service is using a timer
with the OnElapsed
event) ?
Using lock()
or mutex
?
I can't seem to grasp the concept of the mutex
, but using lock()
seems to work fine for my case.
Should I spend the time learning how to use the mutex
anyways?
Instead of lock you can use Monitor.TryEnter() to return if a callback is already being executed by another timer thread:
If all you want is to prevent two threads in the same process/app domain from executing concurrently, the
lock
statement will probably do for you.But note that
lock
leaves the other threads, well, locked while they wait for access to the critical section. They are not aborted or redirected or anything; they are sitting there, waiting for the original thread to finish execution of thelock
block so they may run.A
mutex
would give you greater control; including the ability to have second and subsequent threads just stop altogether, rather than locking, and locking threads across processes.Don't use a timer to spawn threads. Only ever start one thread. When the thread has finished a work cycle, calculate how long remains before the next cycle should start. If this interval is 0 or negative, loop back immediately and start a new cycle, if positive, sleep for that interval before looping back.
This is usually done by taking the int result of an unsigned int subtraction between the finish ticks and start ticks, so giving the elapsed ticks taken by the work. Subtracting this from the desired interval gives the new time remaining.
No extra timer thread needed, no possibility of two threads running simultaneously, simplified overall design, no continual create/start/terminate/destroy, no mallocs, no new(), no stack allocate/deallocate, no GC.
Other designs using timers, mutexes, semaphores, locks etc. are just over complex. Why bother trying to stop the extra threads with synchro if it's just plain easier and simpler to not make any extra threads?
Sometimes, using a timer instead of a sleep() loop is just a really bad idea. This sounds like one of those times.
I think I know what you're trying to do. You've got a timer that executes a callback periodically (definition of a timer) and that callback does a bit of work. that bit of work could actually take more time than the timer period (e.g. the timer period is 500 ms and a given invocation of your callback could take longer that 500 ms). This means that your callback needs to be re-entrant.
If you can't be re-entrant (and there's various reasons why this might be); what I've done in the past is to turn off the timer at the start of the callback then turn it back on at the end. For example:
If you want to actually want one "thread" to execute immediately after another, I wouldn't suggest using a timer; I would suggest using Task objects. For example
I think that some of these approaches are fantastic, but a bit complicated.
I've created a wrapper class that prevents a timer from overlapping and allows you to choose whether "ELAPSED should be called once every INTERVAL" or "An INTERVAL delay should occur between calls".
If you improve on this code, please post the updates here!
Make your timer a one-shot, and re-initialize it in the elapsed event handler. For example, if you're using
System.Timers.Timer
, you'd initialize it like this:And your elapsed event handler:
The drawback to this is that the timer doesn't fire on one second intervals. Rather, it fires one second after the last tick's processing finishes.