This code is buggy.
See the line:
if (Monitor.TryEnter(po1) && Monitor.TryEnter(po2))
Imagine that the lock to
, but for
It will not return, and later will lock
So, when unlocking, it will unlock the wrong number of times.
I really think that if you always lock in the same order with conventional lock:
or if you get rid of one of the locks, you will have better code.
If that's not the case, I think a better implementation will be like this:
Receive an array of objects to lock (so, it can have more than two).
It will create an array of bools of the same size.
At each try, it will only try to lock if lock was not already taken for the given index (using that boolean array).
When locking, it will use
TryEnter(1, ref locksTaken[lockIndex]);
And, if an exception is thrown, it will unlock all already taken locks.
But to be honest, even if this approach never deadlocks, it will timeout to often by "dead-lock" conditions... it is better to enforce lock ordering.