C# 当在锁段内设置的volatile变量的新值对其他线程可用时?

C# 当在锁段内设置的volatile变量的新值对其他线程可用时?,c#,multithreading,C#,Multithreading,我有方法测试,可以从许多线程执行,我不想在方法已经执行时锁定所有想要执行它们的线程。我的想法是创建volatile isProcessing,并在执行处于活动状态时将其设置为true 但我不知道C内存模型,也无法理解其他线程何时会看到iProcessing的新价值。它会在设置isProcessing值后立即执行还是仅在从锁定部分退出后执行 代码示例: private volatile bool isProcessing = false; private void Test() { if (

我有方法测试,可以从许多线程执行,我不想在方法已经执行时锁定所有想要执行它们的线程。我的想法是创建volatile isProcessing,并在执行处于活动状态时将其设置为true

但我不知道C内存模型,也无法理解其他线程何时会看到iProcessing的新价值。它会在设置isProcessing值后立即执行还是仅在从锁定部分退出后执行

代码示例:

private volatile bool isProcessing = false;

private void Test()
{
  if (isProcessing) return;   
  lock(this){
    try{   
      isProcessing = true;
      //do something
    }
    finally{ 
      isProcessing = false;  
    }
  }
}

下面是如何使用两个单独的锁来执行此操作。注意,锁定其他调用站点可能可见的对象不是一个好的做法

    private bool isProcessing = false;
    private object readLock = new object();
    private object processingLock = new object();
    private void Test()
    {
        Monitor.Enter(readLock);
        if (isProcessing)
        {
            Monitor.Exit(readLock);
            return;
        }
        lock (processingLock)
        {
            isProcessing = true;
            Monitor.Exit(readLock);
            try
            {
                //do something
            }
            finally
            {
                isProcessing = false;
            }
        }
    }
一个更简单的解决方案是使用互斥体,而不是使用监视器

    Mutex processingMutex = new Mutex(false);
    private void Test2()
    {
        if (!processingMutex.WaitOne(0))
        {
            return;
        }
        try
        {
            //do processing
        }
        finally
        {
            processingMutex.ReleaseMutex();
        }
    }

互斥锁还允许您通过将参数WaitOne设置为非零值来短暂等待其他线程是否完成。

这不是正确的代码,if-isProcessing测试也需要在锁{}内。这确保锁实现中的隐式内存屏障会更新它。删除volatile以使其正常。低锁方法是联锁的。比较交换。你必须每秒点击这个代码数十万次,才能使它得到回报。@HansPassant,如果我将“isProcessing”检查移到lock部分,所有线程都将被锁定。我的目标不是这样做。首先编写正确的代码,只有在发现有必要时才进行优化。@mjwills,而是//使用RabbitMq连接和对外部系统的http请求进行一些工作。我想,我不能在这里发布这段代码,但这是一种我不想经常并行执行的工作。帮你自己一个忙,使用lock而不使用volatile,即使只是读取值,除非你能证明你有瓶颈。阅读像这样的问题,以及所有的答案和评论,以便弄清楚专家是如何被这些东西弄糊涂的。当您的代码运行在非x86上时,您引入不明错误的可能性大约是10倍,那么您可能会获得某种可测量的性能增益。线程化代码绝对不是进行优化的地方。