5

假设我有两个数组:

int[] array1 = new int[2000000];
int[] array2 = new int[2000000];

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

for(int i = 0; i < 2000000; ++i) array1[i] += array2[i];

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

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

4

6 回答 6

6

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

Parallel.For(0, 2000000, i => { array1[i] += array2[i]; });

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

  • 每个任务(for循环体的执行)都会影响数组的不相交部分
  • Parallel.For等到所有任务完成后再返回,所以会有一个隐式内存屏障。
于 2010-02-19T03:32:20.070 回答
2

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

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

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

于 2010-02-19T01:06:44.510 回答
2

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

您在这里不需要任何特殊处理 - 您将始终处理内存中的相同对象。

此外,由于每个线程将在数组的单独部分上工作,因此不需要锁定。

但是,如果您只是做一个简单的添加,线程化和同步回主线程的开销〜可能​​〜超过获得的好处......如果你这样做,请分析以确保它提供了净收益。

于 2010-02-19T01:07:14.647 回答
2

如果您按照建议将索引范围分解为不重叠的范围,那么如果数组是在共享内存中创建的(即不是由每个线程创建的),则不需要锁。

于 2010-02-19T01:07:47.660 回答
0

如果您在完成修改数组时使用回调,您可能会很好,但是如果有任何问题,使用 Lock 将确保其他线程已经释放了数组。

lock (array1)
{
}

http://msdn.microsoft.com/en-us/library/c5kehkcz(VS.71).aspx

于 2010-02-19T01:03:46.710 回答
0

只要您没有在主线程中复制数组,我认为您不必做任何事情。等到工作线程完成。

于 2010-02-19T01:06:47.737 回答