从多个线程访问数组

时间:2010-02-19 00:59:24

标签: c# caching arrays thread-safety flush

假设我有两个阵列:

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中的值来处理各种重要的事情。 (请注意,两个工作线程可能不会被终止并且可能会被重用,但主线程将不会恢复,直到它们都通知它为止。)

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

6 个答案:

答案 0 :(得分:6)

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

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

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

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

答案 1 :(得分:2)

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

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

如果您需要明确的屏障,请使用Thread.MemoryBarrie r。

答案 2 :(得分:2)

  

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

这里不需要任何特殊处理 - 你将永远处理内存中相同的对象。

此外,由于每个线程都可以在阵列的单独部分上工作,因此不需要锁定。

但是,如果你只是做一个简单的添加,线程和同步回主线程的开销可能会超过所获得的好处......如果你这样做,请进行配置以确保它提供一个网络-Gain。

答案 3 :(得分:1)

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

答案 4 :(得分:0)

如果你在修改数组时使用回调函数你可能会没问题,但是如果有任何问题使用Lock将确保其他线程放弃数组。

lock (array1)
{
}

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

答案 5 :(得分:0)

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