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