锁 - 锁中的2个入口点和1个出口点

时间:2011-09-28 07:17:54

标签: c#

我想重新考虑上一个问题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进行同步。

2 个答案:

答案 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块,并重新订购代码以适应它们。将尽可能少的代码放在块中。