2016-09-30 51 views
3

我需要检查一个Parallel.ForEach的任何迭代是否达到特定点。从我的理解下面将是安全的,如果我的boolvolatile领域,但它需要在外层方法的变量:从C#中的多个线程安全地写入一个bool变量?

bool anySuccess = false; 
Parallel.ForEach(things, thing => 
{ 
    // stuff happens... 
    anySuccess = true; 
}); 
if(!anySuccess) 
    throw new Exception("No things succeeded :("); 

我可以使用此代码按原样或我应该使用lockInterlocked功能?

+0

如果为'anySuccess只写'是将它设置为真,并且直到处理完成之后才会读取它,那么你可能会逃避它。但我会建议使用锁。 – stuartd

+3

您也可以最后使用Volatile.Read(!anySuccess)检查。 – Evk

+0

在这种特定情况下,AnySuccess上可能发生的唯一操作是将其设置为true。这意味着不同线程之间不会有任何竞争条件,例如一个线程将anySuccess设置为false,另一个线程同时将其设置为true。所以在这里你甚至不需要锁定或并行的foreach;即使你在同一时刻开启所有线程,也没有什么不好的事情发生。 – Nebr

回答

3

如果该代码是循环访问该布尔值的ENTIRETY,那么对我而言似乎是安全的。

一般来说基本值类型不是线程安全的,因为对它们执行的许多操作都不是原子的。

但是,如果你曾经做的是分配给该变量ONLY的事情...从来没有阅读它的基础上,它永远不会改变分支的基础上,它从来没有写入它的当前状态......和所有的写是相同的(可能发生的唯一修改是将其设置为true),那么我看不出有任何方式导致非原子性问题。

== ADDITION ==

在当前代码的正确性上述评论。代码在其上下文中作为代码库的一部分的长期安全性也值得考虑。让代码保持原样,为未来的开发人员设置一个陷阱,这个开发人员不知道/理解/识别正在发生的事情,以及为什么它当前是安全的。

如果你这样说,就必须对声明和单一用法做一个CLEAR评论,解释发生了什么,为什么它是安全的,以及为什么他们不开始阅读/使用变量其他方法。

替代方案(添加锁定代码)是长期安全的,但性能可能稍低一些。

+0

如果线程读取anySuccess不会看到它被改变,因为它会读取缓存在CPU寄存器中的值(false)?你不需要Volatile.Read那里? – Evk

+0

@Evk没有东西在读它......这是我答案的全部内容。 – Brondahl

+0

那是怎么回事?如果(!anySuccess)阻止? – Evk

-1

我会锁定布尔。另外,我建议将if语句移动到Parallel.Foreach块中。原因:

这将并行循环后评估,因此只读取的anySuccess

bool anySuccess = false; 
Parallel.ForEach(things, thing => 
{ 
    // stuff happens... 
    anySuccess = true; 
}); 
if(!anySuccess) 
    throw new Exception("No things succeeded :("); 

这最后一次更新将评估布尔的所有更新

Object myLock = new Object(); 

bool anySuccess = false; 
Parallel.ForEach(things, thing => 
{ 
    // stuff happens... 
    lock (myLock) 
    { 
     anySuccess = true; 
    } 
    if(!anySuccess) 
     throw new Exception("No things succeeded :("); 
}); 
+0

这是功能的改变。鉴于anySuccess没有被设置为true的第一个“东西”达到这一点,这将立即终止,即使并非所有的东西都已经被处理。使用原始代码,确保所有事情都得到正确处理。 – Nebr

相关问题