我想重新考虑上一个问题how to obtain a lock in two places but release on one place?,因为它似乎太旧了,没有人看到我更新的代码。
问题是 - 我的代码是否正确,如果没有,如何解决? 我在应用程序中尝试了类似的代码并且它挂了,但我现在不知道为什么,所以我猜我的代码可能还是错的......
public void obtainLock() {
if (needCallMonitorExit == false) {
Monitor.Enter(lockObj);
needCallMonitorExit = true;
}
// doStuff
}
public void obtainReleaseLock() {
try {
lock (lockObj) {
// doAnotherStuff
}
} finally {
if (needCallMonitorExit == true) {
needCallMonitorExit = false;
Monitor.Exit(lockObj);
}
}
}
我的一种方法应该获得锁定。另一种方法应该获得相同的锁并释放它。有时只调用obtainReleaseLock
。有时obtainLock
被调用(可能是几次)并且在调用一段obtainReleaseLock
之后。始终从同一个线程调用这两个方法,但在另一个线程中使用lockObj
进行同步。
答案 0 :(得分:0)
如果你真的需要这样做并且不想使用替代方法provided by Marc,至少要把它放到自己的类中:
public class LockObject
{
object _syncRoot = new object();
object _internalSyncRoot = new object();
public LockToken Lock()
{
lock(_internalSyncRoot)
{
if(!_hasLock)
{
Monitor.Enter(_syncRoot);
_hasLock = true;
}
return new LockToken(this);
}
}
public void Release()
{
lock(_internalSyncRoot)
{
if(!_hasLock)
return;
Monitor.Exit(_syncRoot);
_hasLock = false;
}
}
}
public class LockToken : IDisposable
{
LockObject _lockObject;
public LockToken(LockObject lockObject) { _lockObject = lockObject; }
public void Dispose() { _lockObject.Release(); }
}
这将允许您像这样使用它:
LockObject _lockObj = new LockObject();
public void obtainLock()
{
_lockObj.Lock();
// doStuff
}
public void obtainReleaseLock()
{
using(_lockObj.Lock())
{
// doAnotherStuff
}
}
提醒一句:
如果您的线程在调用obtainLock
之后和调用obtainReleaseLock
之前中止,您的程序将会死锁。
答案 1 :(得分:0)
如果您使用Monitor.Enter
,则需要在同一个线程上对同一对象上的多个Monitor.Exit
调用进行调用。通过使用lock
块,这将自动为您完成 - 只要您超出lock
块的范围,锁定计数就会减少。在同一个线程中,在同一个对象上锁定多次是完全合法的(通过两种机制)。
记住这一点,维护自己的“锁定状态”变量只会使事情变得更复杂。 如果两个线程同时访问 needCallMonitorExit
变量怎么办?
如果我是你,我会坚持lock
块,并重新订购代码以适应它们。将尽可能少的代码放在块中。