从多个线程访问数组

non*_*all 5 c# arrays caching flush thread-safety

假设我有两个数组:

int[] array1 = new int[2000000];
int[] array2 = new int[2000000];
Run Code Online (Sandbox Code Playgroud)

我将一些值粘贴到数组中,然后想将array2的内容添加到array1,如下所示:

for(int i = 0; i < 2000000; ++i) array1[i] += array2[i];
Run Code Online (Sandbox Code Playgroud)

现在,假设我想在多处理器机器上加快处理速度,所以我不是像上面那样进行循环,而是创建两个线程.其中一个我处理了数组中的前1000000个元素,另一个我处理了数组中的最后1000000个元素.我的主线程等待这两个线程通知它已完成,然后继续使用array1中的值来处理各种重要的事情.(请注意,两个工作线程可能不会被终止并且可能会被重用,但主线程将不会恢复,直到它们都通知它为止.)

所以,我的问题是:我如何确定主线程将看到两个工作线程对数组所做的修改?我可以指望这种情况发生吗?或者我是否需要通过一些特殊的过程来确保工作线程刷新它们对数组的写入并且主线程丢弃其缓存的数组值?

Tom*_*cek 6

如果你很幸运并且可以选择使用.NET 4.0,那么你可以写:

Parallel.For(0, 2000000, i => { array1[i] += array2[i]; });
Run Code Online (Sandbox Code Playgroud)

您不需要任何显式锁定或同步,因为:

  • 每个任务(for循环体的执行)都会影响数组的不相交部分
  • Parallel.For 等到所有任务在返回之前完成,因此会有一个隐含的内存屏障.


Mic*_*ael 2

您需要一个内存屏障来确保工作线程对数组的写入按您期望的顺序对主线程可见。

是否需要显式内存屏障取决于您如何通知主线程。等待大多数同步原语(例如事件)会提供隐式屏障,因此您无需进行任何更改。轮询全局变量不会提供障碍。

如果需要显式屏障,请使用Thread.MemoryBarrie r。

  • 鉴于他计划阻塞主线程(根据描述),内存屏障应该是不必要的。 (2认同)