Part of my code-behind:
object _sync = new object();
private async void OnKeyDown(object sender, KeyEventArgs e) {
if (!Monitor.TryEnter(_sync)) return;
Trace.Write("taken...");
await Task.Delay(TimeSpan.FromSeconds(5));
Trace.WriteLine(" done");
Monitor.Exit(_sync);
}
Output (pressing several times in less than 5 seconds):
taken...taken...taken... done
done
done
How-come?? the _sync
lock is never being taken, why?
TryEnter(Object, TimeSpan, Boolean) Attempts, for the specified amount of time, to acquire an exclusive lock on the specified object, and atomically sets a value that indicates whether the lock was taken. TryEnter(Object, Int32, Boolean)
CSharp Online Training Both Monitor and lock provides a mechanism that synchronizes access to objects. lock is the shortcut for Monitor. Enter with try and finally. Lock is a shortcut and it's the option for the basic usage.
Exit() : Releases an exclusive lock on the specified object. This action also marks the end of a critical section protected by the locked object.
Mixing Monitor
and await
is... more than a little risky. It looks like what you are trying to do is to ensure it only runs once at a time. I suspect Interlocked
may be simpler:
object _sync = new object();
int running = 0;
private async void OnKeyDown(object sender, KeyEventArgs e) {
if(Interlocked.CompareExchange(ref running, 1, 0) != 0) return;
Trace.Write("taken...");
await Task.Delay(TimeSpan.FromSeconds(5));
Trace.WriteLine(" done");
Interlocked.Exchange(ref running, 0);
}
Note you might also want to think what happens if an error occurs etc; how does the value become reset? You can probably use try
/finally
:
if(Interlocked.CompareExchange(ref running, 1, 0) != 0) return;
try {
Trace.Write("taken...");
await Task.Delay(TimeSpan.FromSeconds(5));
Trace.WriteLine(" done");
} finally {
Interlocked.Exchange(ref running, 0);
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With