非阻塞锁 [英] Non blocking locking

查看:172
本文介绍了非阻塞锁的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我要开始新的一些新的主题进行一个重复操作。但是,当这样的操作已经在进行中,我想放弃当前任务。在我的情况,我需要非常当前的数据只是 - 下降的数据是不是一个问题。

在MSDN,我发现了互斥类,但据我所知,它等待轮到它,阻止当前线程。此外,我要问你:的东西是否存在已经是.NET框架,即做以下

  1. 在一些子程序M已经被执行?
  2. 如果是这样,返回(让我增加一些反统计)
  3. 如果没有,启动方法M在一个新的线程
解决方案

锁(someObject)语句,你可能会遇到的,是语法左右<$糖C C> Monitor.Enter 和 Monitor.Exit

不过,如果您使用的显示器在此更详细的方法,你也可以使用 Monitor.TryEnter ,它允许你检查你就可以得到锁定 - 因此,检查是否有人已经拥有它,并正在执行code

而不是此

所以:

  VAR lockObject =新的对象();

锁定(lockObject)
{
    //做一些东西
}
 

试试这个(选项1)

  INT _alreadyBeingExecutedCounter;
VAR lockObject =新的对象();

如果(Monitor.TryEnter(lockObject))
{
   //你只在这里结束,如果你得到了锁,当你试图得到它 - 否则,你永远也不会执行该code。

    //做一些东西

    //调用exit释放锁
    Monitor.Exit(lockObject);
}
其他
{
    //没有得到锁 - 别人正在执行的code以上 - 所以我不需要做任何工作!
   Interlocked.Increment(REF _alreadyBeingExecutedCounter);
}
 

(你可能会希望把一个try..finally在那里,以确保锁被释放)

或免除明确锁定althogether而做到这一点

(选项2)

 私人诠释_inUseCount;

公共无效的MyMethod()
{
    如果(Interlocked.Increment(参考_inUseCount)== 1)
    {
        //做穹顶东西
    }
    Interlocked.Decrement(REF _inUseCount);
}
 

没有 - 不使用上锁定。创建一个私人范围的对象作为你的锁。

否则,你有这个潜在的问题:

 公共类MyClassWithLockInside
{
    公共无效MethodThatTakesLock()
    {
        锁(本)
        {
            //做一些工作
        }
    }
 }

公共类消费
{
    私有静态MyClassWithLockInside _instance =新MyClassWithLockInside();

    公共无效ThreadACallsThis()
    {
          锁(_instance)
          {
              //已经采取了锁在我们的MyClassWithLockInside的情况下,
              //做一些长时间运行
              Thread.sleep代码(6000);
           }
    }

    公共无效ThreadBCallsThis()
    {
         //如果线程B调用此同时,线程A仍然是内锁上面,
         //因为它试图对同一对象获取锁定这个方法会阻塞
         // [本之类的内部= _instance外]
         _instance.MethodThatTakesLock();
    }
}
 

在上面的例子中,一些外部code已设法破坏我们类的内部锁定只是通过取出的东西的锁定,这是外部可访问的

最好创建你控制一个私有对象,而且没有一类的外部访问,以避免这些类型的问题;这包括不使用或类型本身的typeof(MyClassWithLockInside)锁定。

I want to start some new threads each for one repeating operation. But when such an operation is already in progress, I want to discard the current task. In my scenario I need very current data only - dropped data is not an issue.

In the MSDN I found the Mutex class but as I understand it, it waits for its turn, blocking the current thread. Also I want to ask you: Does something exist in the .NET framework already, that does the following:

  1. Is some method M already being executed?
  2. If so, return (and let me increase some counter for statistics)
  3. If not, start method M in a new thread

解决方案

The lock(someObject) statement, which you may have come across, is syntactic sugar around Monitor.Enter and Monitor.Exit.

However, if you use the monitor in this more verbose way, you can also use Monitor.TryEnter which allows you to check if you'll be able to get the lock - hence checking if someone else already has it and is executing code.

So instead of this:

var lockObject = new object(); 

lock(lockObject)
{
    // do some stuff
}

try this (option 1):

int _alreadyBeingExecutedCounter;
var lockObject = new object();

if (Monitor.TryEnter(lockObject))
{
   // you'll only end up here if you got the lock when you tried to get it - otherwise you'll never execute this code.

    // do some stuff

    //call exit to release the lock
    Monitor.Exit(lockObject);
}
else
{
    // didn't get the lock - someone else was executing the code above - so I don't need to do any work!
   Interlocked.Increment(ref _alreadyBeingExecutedCounter);
}

(you'll probably want to put a try..finally in there to ensure the lock is released)

or dispense with the explicit lock althogether and do this

(option 2)

private int _inUseCount;

public void MyMethod()
{
    if (Interlocked.Increment(ref _inUseCount) == 1)
    {
        // do dome stuff    
    }
    Interlocked.Decrement(ref _inUseCount);
}

[Edit: in response to your question about this]

No - don't use this to lock on. Create a privately scoped object to act as your lock.

Otherwise you have this potential problem:

public class MyClassWithLockInside
{
    public void MethodThatTakesLock()
    {
        lock(this)
        {
            // do some work
        }
    }
 }

public class Consumer
{
    private static MyClassWithLockInside _instance = new MyClassWithLockInside();

    public void ThreadACallsThis()
    {
          lock(_instance)
          {
              // Having taken a lock on our instance of MyClassWithLockInside,
              // do something long running
              Thread.Sleep(6000);
           }
    }

    public void ThreadBCallsThis()
    {
         // If thread B calls this while thread A is still inside the lock above,
         // this method will block as it tries to get a lock on the same object
         // ["this" inside the class = _instance outside]
         _instance.MethodThatTakesLock();
    }  
}

In the above example, some external code has managed to disrupt the internal locking of our class just by taking out a lock on something that was externally accessible.

Much better to create a private object that you control, and that no-one outside your class has access to, to avoid these sort of problems; this includes not using this or the type itself typeof(MyClassWithLockInside) for locking.

这篇关于非阻塞锁的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆