Here are three different ways to turn off a dead end. This list is not exhaustive.
Call the lock method from the lock section.
In this example, thread A gets a lock, and then immediately calls the lock method, while thread B tries to get the same lock, but gets a hang because thread A waits for thread B to signal an event before it will release the lock.
public class Example { ManualResetEvent m_Event = new ManualResetEvent(false); void ThreadA() { lock (this) { m_Event.WaitOne(); } } void ThreadB() { lock (this) { m_Event.Set(); } } }
Get two locks out of order.
No explanation is required here, as this is a well-known problem.
public class Example { private object m_LockObjectA = new object(); private object m_LockObjectB = new Object(); void ThreadA() { lock (m_LockObjectA) lock (m_LockObjectB) { } } void ThreadB() { lock (m_LockObjectB) lock (m_LockObjectA) { } } }
Lockable dead end.
This is one of my favorite illustrations of the dead end because the lock or block method is not involved. The subtleties of the problem are enough to confuse even those who are familiar with threads. The problem here is the lack of memory barriers. Thread A expects thread B to set a signal flag, while thread B waits for thread A to reset all the time until one thread sees the changes that the other makes, because the compiler, JIT, and hardware are free to optimize reading and writing flag in a way that is not intuitive.
public class Example { private bool m_Signal = false; void ThreadA() { while (!m_Signal); m_Signal = false; } void ThreadB() { m_Signal = true; while (m_Signal); } }
Brian gideon
source share