首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >非阻塞锁定

非阻塞锁定
EN

Stack Overflow用户
提问于 2012-02-09 10:58:12
回答 4查看 7K关注 0票数 9

我想启动一些新线程,每个线程用于一个重复操作。但是,当这一行动已经在进行时,我想放弃目前的任务。在我的场景中,我只需要非常最新的数据-删除的数据不是一个问题。

在MSDN中,我找到了Mutex类,但据我所知,它等待它的回合,阻塞当前线程。另外,我想问您:在.NET框架中已经存在一些东西,即执行以下

  1. 有什么方法M已经被执行了吗?
  2. 如果是这样的话,return (让我增加一些统计计数器)
  3. 如果没有,则在新线程中启动方法M。
EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2012-02-09 11:17:42

您可能遇到过的lock(someObject)语句是Monitor.EnterMonitor.Exit周围的语法糖。

但是,如果您以这种更详细的方式使用监视器,您还可以使用Monitor.TryEnter,它允许您检查是否能够获得锁--从而检查其他人是否已经拥有它并正在执行代码。

所以,不是这样的:

代码语言:javascript
复制
var lockObject = new object(); 

lock(lockObject)
{
    // do some stuff
}

试试这个(选项1)

代码语言:javascript
复制
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);
}

(您可能希望在其中放置一个try..finally,以确保锁被释放)

或取消显式锁althogether并执行此操作。

(选项2)

代码语言:javascript
复制
private int _inUseCount;

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

this**]** [编辑:回答你关于的问题

不-不要用this来打开lock。创建一个私有的作用域对象作为您的锁。

否则,您将遇到以下潜在问题:

代码语言:javascript
复制
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();
    }  
}

在上面的例子中,一些外部代码成功地破坏了类的内部锁定,只需取出一个外部可访问的锁。

更好的方法是创建一个您控制的私有对象,并且您的类之外的任何人都不能访问该对象,以避免此类问题;这包括不使用this或类型本身typeof(MyClassWithLockInside)进行锁定。

票数 24
EN

Stack Overflow用户

发布于 2012-02-09 11:19:26

一种选择是使用可重入的哨兵:

您可以定义一个int字段(用0初始化),并在输入该方法时通过Interlocked.Increment更新它,只有当它为1时才继续,最后只需执行Interlocked.Decrement

另一种选择:

从你的描述来看,你似乎有一个制片人-消费者-场景.

在这种情况下,使用像BlockingCollection这样的东西可能会有帮助,因为它是线程安全的,而且大多是无锁的.

另一种选择是使用ConcurrentQueueConcurrentStack.

票数 2
EN

Stack Overflow用户

发布于 2012-02-09 11:16:25

您可能会在下面的站点中找到一些有用的信息( PDf也是可下载的--最近我自己下载了)。Adavnced线程挂起,并继续或中止章节,可能是什么你不知道。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/9209590

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档