我需要检查Parallel.ForEach
的任何迭代是否到达特定点。根据我的理解,如果我的bool
是volatile
字段,则以下内容是安全的,但它必须是封闭方法中的变量:
bool anySuccess = false;
Parallel.ForEach(things, thing =>
{
// stuff happens...
anySuccess = true;
});
if(!anySuccess)
throw new Exception("No things succeeded :(");
我可以按原样使用此代码,还是应该使用lock
或Interlocked
功能?
答案 0 :(得分:3)
如果该代码是循环访问该布尔值的 ENTIRETY ,那么对我来说似乎是安全的。
通常基本值类型在某些意义上不是线程安全的,因为对它们执行的许多操作都不是原子的。
但是,如果您正在做的 ONLY 事情是分配给该变量......从不读它,永远不要根据它改变分支,永远不要根据它的当前状态写入它。并且所有写入都是相同的(唯一可能发生的修改是将其设置为true
)然后我没有看到任何非原子性导致问题的方法。
<强> == ADDITION == 强>
以上对当前代码的正确性的评论。作为代码库的一部分,还需要考虑代码在其上下文中的长期安全性。让代码保持原样,正在为未知的开发人员设置一个陷阱,他不了解/了解/识别正在发生的事情,以及为什么它当前是安全的。
如果你这样离开,那么必须对声明和单一用法进行CLEAR评论,说明发生了什么,为什么它是安全的,以及为什么他们不能开始阅读/使用其他变量方式。
替代方案(添加锁定代码)是长期更安全的,但也可能性能稍差。
答案 1 :(得分:-2)
我会锁定布尔。另外,我建议将你的if语句移动到Parallel.Foreach块中。原因是:
这将在并行循环之后进行评估,因此只读取anySuccess的最后一次更新
bool anySuccess = false;
Parallel.ForEach(things, thing =>
{
// stuff happens...
anySuccess = true;
});
if(!anySuccess)
throw new Exception("No things succeeded :(");
这将评估bool的所有更新
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 :(");
});