开发者

How to release a lock and acquire another atomicly

In my application I manage a collection of locks that I need to serialize access to some of objects (each object is assigned a lock). This collection of locks (lock manager) also needs to be maintained in a thread-safe fashion (new locks are added/old locks are removed as new objects which require serialization are added/removed). The algorithm works something like this:

LockManager.Lock();
var myLock = LockManager.FindLock(myObject);
LockManager.Unlock();                          // atomic
myLock.Lock();                                 // atomic

Swapping two lines is not a good solution. If locking of myLock would block then this would also block unlocking of LockManager making any requests for other locks to block.

Wh开发者_如何学Cat I would need is that the two marked lines are executed atomically. Is there a way to achieve this?


So you want to:

  • guarantee that the individual lock (via myLock) was entered
  • then unlock the LockManager
  • make the above two operations atomic
  • and not allow this new atomic operation to block if the individual lock cannot be entered immediately

Similar to how you cannot circumvent the laws of physics to create a perpetual motion machine you also cannot circumvent the laws of computation by executing a sequence of operations atomically in such manner that it does not block even if one of its constituents can, in fact, be expected to block. In other words, there is no way to make the operation complete until the individual parts also complete.

However, what we can do is attempt this atomic operation in an all-or-none manner that never blocks as long as we are okay with the "none" outcome. You see this a lot with the TryXXX methods that exist on a lot of concurrent data structures. All you would need to do is define a TryLock on your myLock type. Then, the LockManager could look like the following.

public class LockManager
{
  public bool TryEnterIndividualLock(object value)
  {
    Lock();
    try
    {
      var myLock = FindLock(value);
      if (myLock != null)
      {
        return myLock.TryLock();
      }
      return false;
    }
    finally
    {
      Unlock();
    }
  }  
}

Then the calling code would look like this:

while (!LockManager.TryEnterIndividualLock(myObject))
{
  // Do something else until the lock can be entered.
}

This would give you the atomicity you were looking for, but at the cost of the operation not succeeding. If you are relying on this operation succeeding immediately then you are going to have to rethink your overall design.

0

上一篇:

下一篇:

精彩评论

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

最新问答

问答排行榜