Reputation: 861
I have a question that is easily solvable in C++, but in C# I still can’t find a good solution:
I have a function foo that need to lock two objects and this function can be called with arguments in the opposite order, e.g.:
static void foo(object o1, object o2)
{
lock (o1)
{
lock (o2)
{
...
}
}
}
static void bar(object a, object b)
{
ThreadPool.QueueUserWorkItem(s => foo(a, b));
ThreadPool.QueueUserWorkItem(s => foo(b, a));
}
This is a by-the-book way to make a deadlock. The standard way to fix this is to always lock objects in the same order. In C++, I could compare pointers but in “safe” C# I don’t know any way but a very ugly Monitor.TryEntry
solution (see below). Is there anything better? Please note that objects are mutable and I can’t rely on Equals
, GetHashCode
, IComparable
.
static void foo(object o1, object o2)
{
const int Timeout = 1000;
while (true)
{
if (Monitor.TryEnter(o1, Timeout))
{
try
{
if (Monitor.TryEnter(o2, Timeout))
{
try
{
...
return;
}
finally
{
Monitor.Exit(o2);
}
}
}
finally
{
Monitor.Exit(o1);
}
}
}
}
Upvotes: 4
Views: 1423
Reputation: 100527
If you want the same ordered lock approach you can add some property to the object you are using for locking and compare based on it. You can use classes or interfaces depending what works in your case (i.e. implement IComparable
on locking objects). Sample below uses class with Less
comparing function:
class ComparableLockingObject
{
static int LastOrderValue = 0;
private orderValue = LastOrderValue++;
public bool Less(ComparableLockingObject other)
{
return this.orderValue < other.orderValue;
}
}
static void foo(ComparableLockingObject o1, ComparableLockingObject o2,
Action action)
{
if (o2.Less(o1))
{
var temp = o1;
o1 = o2;
o2 = temp;
}
lock (o1)
{
lock (o2)
{
action();
}
}
}
Upvotes: 3
Reputation: 19340
You don't need to lock these objects. You lock the code that executes the logic:
static object lockObject = new object();
static void foo(object o1, object o2)
{
lock (lockObject)
{
// this code will be executed on one thread at the time. Why lock o1 & o2??
}
}
Upvotes: 2