Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Monitor, lock or volatile?

I have a windows service (.NET 4) that periodically processes a queue, for example every 15 minutes. I use a System.Threading.Timer which is set when the service starts to fire a callback every X milliseconds. Typically each run takes seconds and never collides, but what if I could not assume that - then I want the next run to exit at once if processing is in progress.

This is easily solved with lock, volatile bool or a monitor, but what is actually the appropriate to use in this scenario, or simply the preferred option in general?

I've found other posts that answers almost this scenario (like Volatile vs. Interlocked vs. lock) but need some advice on extending this to a Timer example with immediate exit.

like image 209
krembanan Avatar asked Jun 24 '13 09:06

krembanan


People also ask

What is the difference between volatile and synchronized?

So where volatile only synchronizes the value of one variable between thread memory and "main" memory, synchronized synchronizes the value of all variables between thread memory and "main" memory, and locks and releases a monitor to boot. Clearly synchronized is likely to have more overhead than volatile.

Do I need volatile with synchronized?

When to use Volatile over Synchronized modifiers can be summed up into this: Use Volatile when you variables are going to get read by multiple threads, but written to by only one thread. Use Synchronized when your variables will get read and written to by multiple threads.

Is volatile thread safe?

Using volatile is yet another way (like synchronized, atomic wrapper) of making class thread-safe. Thread-safe means that a method or class instance can be used by multiple threads at the same time without any problem.

When should I use volatile in Java?

When to use it? You can use a volatile variable if you want to read and write long and double variable automatically. It can be used as an alternative way of achieving synchronization in Java. All reader threads will see the updated value of the volatile variable after completing the write operation.


2 Answers

You don't need any locks for this, you should just reschedule next timer execution from within the timer delegate. That should ensure 100% no overlaps.

At the end of timer's event handler call timer.Change(nextRunInMilliseconds, Timeout.Infinite), that way the timer will fire only once, after nextRunInMilliseconds.

Example:

//Object that holds timer state, and possible additional data
private class TimerState
{
    public Timer Timer { get; set; }
    public bool Stop { get; set; }
}

public void Run()
{
    var timerState = new TimerState();
    //Create the timer but don't start it
    timerState.Timer = new Timer(OnTimer, timerState, Timeout.Infinite, Timeout.Infinite);
    //Start the timer
    timerState.Timer.Change(1000, Timeout.Infinite);
}

public void OnTimer(object state)
{
    var timerState = (TimerState) state;            
    try
    {
        //Do work
    }
    finally 
    {
        //Reschedule timer
        if (!timerState.Stop)
            timerState.Timer.Change(1000, Timeout.Infinite);
    }
}
like image 177
Boris B. Avatar answered Oct 09 '22 17:10

Boris B.


Well, any of them will do the job. Monitor is usually pretty simple to use via lock, but you can't use lock in this case because you need to specify a zero timeout; as such, the simplest approach is probably a CompareExchange:

private int isRunning;
...
if(Interlocked.CompareExchange(ref isRunning, 1, 0) == 0) {
    try {
        // your work
    } finally {
        Interlocked.Exchange(ref isRunning, 0);
    }
}

to do the same with Monitor is:

private readonly object syncLock = new object();
...
bool lockTaken = false;
try {
    Monitor.TryEnter(syncLock, 0, ref lockTaken);
    if (lockTaken) {
        // your work
    }
} finally {
    if(lockTaken) Monitor.Exit(syncLock);
}
like image 20
Marc Gravell Avatar answered Oct 09 '22 16:10

Marc Gravell