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

C# 如何在一个原子操作中执行布尔值的读取和写入?,c#,C#,假设我有一个被多个线程调用的方法 public class MultiThreadClass { public void Gogogo() { // method implementation } private volatile bool running; } 在Gogogo()中,我想检查running是否为true,如果为true,则从该方法返回。但是,如果为false,我希望将其设置为true并继续该方法。我看到的解决方案是执行以下操作

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

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

    private volatile bool running;
}
在Gogogo()中,我想检查
running
是否为true,如果为true,则从该方法返回。但是,如果为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();
}
还有别的办法吗?我发现,如果我省略了锁,
对两个不同的线程运行
可能是false,设置为true,方法的其余部分将同时在两个线程上执行

我想我的目标是让方法的其余部分在单个线程上执行(我不在乎是哪个线程),而不被其他线程执行,即使所有线程(本例中为2-4个)同时调用Gogogo()

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


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

我认为应该这样做。

如果您确实想:


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

您可以使用
interlocted。如果将bool更改为int,则比较交换

private volatile int running = 0;

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

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

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

}

你看过
Interlocated
?我想说知道怎么做很酷。但是,几乎可以肯定是微优化。如果你还没有运行代码分析来确定这段代码确实是一个瓶颈,那么一定是微优化。在被证明有罪之前是无辜的。谢谢Servy。为什么Interlocated没有bool重载?看起来它们会很有用(这样我就不必用
1
0
来表示真与假)。@SamPearson谁知道呢。他们只是没有花时间来实现它。这不会导致在另一个方法运行时调用此方法来跳过所请求的方法体。
public void Gogogo()
{
    if Monitor.TryEnter(this.locker)
    { 
         try 
         { 
              // Do stuff
         } 
         finally 
         {
            Monitor.Exit(this.locker); 
         } 
    }

}