开发者

lock - 2 entrance point in the lock and 1 exit point [duplicate]

This question already has answers here: how to obtain a lock in two places but release on one place? (4 answers) Closed 8 years ago.

I want to reask my previous question how to obtain a lock in two places but release on one place? because it seems too old and noone sees my updated code.

The question is - is my code correct and how to fix it if not? I've tried similar code in the application and it hangs, but I don't now why, so I guess probably my code still wrong...

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);
        }
    }
}

One of my methods should obtain the lock. another method should obta开发者_开发百科in the same lock and release it. sometimes just obtainReleaseLock is called. sometimes obtainLock is called (probably several times) and after a while obtainReleaseLock is called. These two methods are always called from the same thread, however lockObj is used in another thread for synchronization.


If you really need to go this way and don't want to use the alternatives provided by Marc, at least, put it into its own class:

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(); }
}

This would allow you to use it like this:

LockObject _lockObj = new LockObject();

public void obtainLock()
{
    _lockObj.Lock();
    // doStuff
}

public void obtainReleaseLock()
{
    using(_lockObj.Lock())
    {
        // doAnotherStuff
    }
}

One word of caution:

If your thread is aborted after the call to obtainLock and before the call to obtainReleaseLock, your program will deadlock.


If you use Monitor.Enter you will need to call exactly that many Monitor.Exit calls on the same object, on the same thread. By using a lock block this is automatically done for you - as soon as you are outside the scope of the lock block, the lock count is decreased. Within the same thread it is perfectly legal to lock multiple times on the same object (via both mechanisms).

Keeping that in mind, maintaining your own "lock state" variable would only make things more complex. What if two threads access the needCallMonitorExit variable at the same time?

If I were you I would stick to lock blocks, and re-order code to fit inside them. Put as little code inside the blocks as possible.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜