在开始之前,我应该提一下,我觉得我搞错了方向。但无论如何,我们还是开始吧:
假设我们有以下类(class):
public class SomeObject {
public int SomeInt;
private SomeObject anotherObject;
public void DoStuff() {
if (SomeCondition()) anotherObject.SomeInt += 1;
}
}
现在,假设我们有这些 SomeObject
的集合s:
IList<SomeObject> allObjects = new List<SomeObject>(1000);
// ... Pretend the list is populated with 1000 SomeObjects here
假设我打电话 DoStuff()
在每一个上,就像这样:
foreach (var @object in allObjects) @object.DoStuff();
到目前为止一切都很好。
现在,我们假设对象的顺序是 DoStuff()
叫什么并不重要。假设SomeCondition()
也许在计算上是昂贵的。我可以利用我的机器上的所有四个核心(并可能获得性能提升):
Parallel.For(0, 1000, i => allObjects[i].DoStuff());
现在,忽略变量访问原子性的任何问题,我不在乎在循环中是否有任何给定的 SomeObject
看到 anotherObject
的过时版本或SomeInt
.* 但是,一旦循环完成,我想确保我的主工作线程(即调用 Parallel.For 的线程)确实看到所有内容都是最新的。
使用 Parallel.For 是否能保证这一点(例如某种内存屏障?)?还是我自己需要做某种保证?或者说没有办法做出这样的保证?
最后,如果我调用Parallel.For(...)
之后再次以同样的方式,所有工作线程都会使用新的、最新的值吗?
(*) DoStuff()
的实现者无论如何,对处理顺序做出假设都是错误的,对吗?
最佳答案
var locker = new object();
var total = 0.0;
Parallel.For(1, 10000000,
i => { lock (locker) total += (i + 1); });
Console.WriteLine("WithLocker" + total);
var total2 = 0.0;
Parallel.For(1, 10000000,
i => total2 += (i + 1));
Console.WriteLine("WithoutLocker" + total2);
Console.ReadKey();
// WithLocker 50000004999999
// WithoutLocker 28861729333278
我为你做了两个例子,一个带储物柜,一个不看结果!
关于c# - 并行操作的线程安全,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18677539/