How long will a C# lock wait, and what if the code crashes during the lock?
When another thread comes by and wants to execute the code, how long will it wait until the lock is released?
lock
will block the the thread trying to enter the lock indefinitely until the object being locked on is released.
can you somehow set a timeout?
If you need to specify a timeout, use Monitor.TryEnter
as in
if(Monitor.TryEnter(obj, new TimeSpan(0, 0, 1))) {
try {
body
}
finally {
Monitor.Exit(obj);
}
}
if the
DoIt()
method throws an exception, is the lock still released?
Yes, a lock(obj) { body }
is translated to:
bool lockWasTaken = false;
var temp = obj;
try { Monitor.Enter(temp, ref lockWasTaken); { body } }
finally { if (lockWasTaken) Monitor.Exit(temp); }
For the gory details on what can happen when an exception is thrown, see Locks and exceptions do not mix.
As mentioned, a regular lock will wait forever, which is a risk of deadlocks.
The preferred mechanism is (and note the ref
):
bool lockTaken = false;
try {
Monitor.TryEnter(lockObj, timeout, ref lockTaken);
if(!lockTaken) throw new TimeoutException(); // or compensate
// work here...
} finally {
if(lockTaken) Monitor.Exit(lockObj);
}
This avoids the risk of not releasing the lock in some edge-cases.
The finally
(which exists in any sensible implementation) ensures the lock is released even in error conditions.
A simple lock(syncRoot)
will wait forever.
You can replace it with
if (System.Threading.Monitor.TryEnter(syncRoot, 1000))
{
try
{
DoIt();
}
finally
{
System.Threading.Monitor.Exit(syncRoot);
}
}
Every thread should ensure exception-safe locking.
Note that the standard lock(syncRoot) {}
is rewritten to Monitor.Enter(syncRoot)
and a try/finally