I have an array of my own classes, with size N
. Each instance can reference other instances in the array, and holds a list of indices in the list.
class A
{
public List<int> References { get; } = new List<int>();
}
A[] a_array = new A[N];
I want to create a smart locking system - an array with size N
, where in each index I hold a lock for each instance in a_array
. Whenever I update or read an instance in a_array
I need to lock the instance and all its references.
object[] locks = new object[N];
foreach (var refer in a.References)
{
// lock locks[refer];
}
How do I lock multiple objects in C#, when the number of locks per instance is variable (The number of references can be different for each A
instance)
I know I can use Mutex for this, but I want to make sure the mutex is released whenever an exception is thrown in my code.
CodePudding user response:
lock
is just shorthand for Monitor.Enter
in a try/finally with a Monitor.Exit
at the end. You can just do that explicitly in a loop.
Providing a lambda of the critical section means that the entire lock management is tightly encapsulated, making it harder to forget to properly release locks.
public static void LockAll(IEnumerable<object> lockObjects, Action action)
{
List<object> enteredLocks = new List<object>();
try
{
foreach (var lockObject in lockObjects)
{
Monitor.Enter(lockObject);
enteredLocks.Add(lockObject);
}
action();
}
finally
{
foreach (var lockObject in enteredLocks)
Monitor.Exit(lockObject);
}
}
public static T LockAll<T>(IEnumerable<object> lockObjects, Func<T> func)
{
List<object> enteredLocks = new List<object>();
try
{
foreach (var lockObject in lockObjects)
{
Monitor.Enter(lockObject);
enteredLocks.Add(lockObject);
}
return func();
}
finally
{
foreach (var lockObject in enteredLocks)
Monitor.Exit(lockObject);
}
}
As with any situation where you lock on multiple things, you need to ensure you always lock on items in a consistent ordering to avoid deadlocks.