如何在一个原子操作中执行布尔值的读取和写入?

时间:2014-03-10 20:23:11

标签: c#

假设我有一个被多个线程调用的方法

public class MultiThreadClass
{
    public void Gogogo()
    {
        // method implementation
    }

    private volatile bool running;
}

在Gogogo()中,我想检查running是否为真,如果是,则从方法返回。但是,如果它是false,我想将其设置为true并继续该方法。我看到的解决方案是执行以下操作:

public class MultiThreadClass
{
    public void Gogogo()
    {
        lock (this.locker)
        {
            if (this.running)
            {
                return;
            }

            this.running = true;
        }

        // rest of method

        this.running = false;
    }

    private volatile bool running;
    private readonly object locker = new object();
}

还有其他办法吗?我发现如果我省略了锁,running可能对于2个不同的线程是假的,设置为true,并且该方法的其余部分将同时在两个线程上执行。

我想我的目标是让我的方法的其余部分在一个线程上执行(我不关心哪一个)并且不被其他线程执行,即使所有这些都是(在这种情况下为2-4) )同时打电话给Gogogo()。

我也可以锁定整个方法,但方法运行速度会慢吗?它需要尽可能快地运行,但一部分只能在一个线程上运行。

(详细信息:我有一个ConcurrentQueue的词典,其中包含“结果”,其中包含“作业名称”。我试图将每个键中的一个结果出列(每个作业名称一个结果)并将其称为“完整结果” “由事件发送给订阅者。结果通过事件发送到类,并且该事件从多个线程引发(每个作业名称一个;每个作业在其自己的线程上引发”结果就绪“事件)< / p>

4 个答案:

答案 0 :(得分:1)

我认为Interlocked.Exchange可以做到这一点。

答案 1 :(得分:1)

如果您 想要

,则可以使用Interlocked来处理此情况,而不是lock

public class MultiThreadClass
{
    public void Gogogo()
    {
        if (Interlocked.Exchange(ref running, 1) == 0)
        {
            //Do stuff

            running = 0;
        }
    }

    private volatile int running = 0;
}

那就是说,除非有一个非常高的争用率(我不指望),那么你的代码应该是完全足够的。使用Interlocked在可读性部门也会受到一些影响,因为他们的方法没有bool重载。

答案 2 :(得分:1)

如果将bool更改为int:

,则可以使用Interlocked.CompareExchange
private volatile int running = 0;

if(Interlocked.CompareExchange(ref running, 1, 0) == 0)
{
    //running changed from false to true
}

答案 3 :(得分:0)

您需要使用Monitor类而不是boolean标志。使用Monitor.TryEnter:

public void Gogogo()
{
    if Monitor.TryEnter(this.locker)
    { 
         try 
         { 
              // Do stuff
         } 
         finally 
         {
            Monitor.Exit(this.locker); 
         } 
    }

}