从多个线程访问数组
假设我有两个数组:
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 中的值来处理各种重要的事情。 (请注意,两个工作线程可能不会终止并且可以重用,但主线程不会恢复,直到它们都通知它这样做。)
所以,我的问题是:我如何确定主线程将 恢复看到两个工作线程对数组所做的修改了吗?我可以指望这种情况发生吗?或者我是否需要执行一些特殊的过程来确保工作线程将其写入数组刷新,并且主线程丢弃其缓存的数组值?
Let's say I have two arrays:
int[] array1 = new int[2000000];
int[] array2 = new int[2000000];
I stick some values into the arrays and then want to add the contents of array2 to array1 like so:
for(int i = 0; i < 2000000; ++i) array1[i] += array2[i];
Now, let's say I want to make processing faster on a multi-processor machine, so instead of just doing a loop like above, I create two threads. One of which I have process the first 1000000 elements in the array, the other I have process the last 1000000 elements in the array. My main thread waits for those two threads to notify it that they are finished, and then proceeds to use the values from array1 for all kinds of important stuff. (Note that the two worker threads may not be terminated and may be reused, but the main thread will not resume until they have both notified it to do so.)
So, my question is: How can I be sure that the main thread will see the modifications that the two worker threads made to the array? Can I count on this to happen or do I need to go through some special procedure to make sure the worker threads flush their writes to the array and the main thread discards its cached array values?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
如果您很幸运并且可以选择使用 .NET 4.0,那么您可以只写:
您不需要任何显式锁定或同步,因为:
for
循环体的执行)影响数组的不相交部分Parallel.For
会等到所有任务完成后才返回,因此会存在隐式内存屏障。If you're lucky and have the option to use .NET 4.0 then you can just write:
You don't need any explicit locking or synchronization, because:
for
loops body) affects disjoint part of the arrayParallel.For
waits until all tasks finish before it returns, so there will be an implicit memory barrier.您需要一个内存屏障来确保工作线程对数组的写入按您期望的顺序对主线程可见。
是否需要显式内存屏障取决于您如何通知主线程。等待大多数同步原语(例如事件)会提供隐式屏障,因此您无需进行任何更改。轮询全局变量不会提供障碍。
如果需要显式屏障,请使用 Thread.MemoryBarrie< /a>r.
You need a memory barrier to ensure that the worker thread's writes to the array are visible to the main thread in the order you expect.
Whether or not you need an explicit memory barrier depends on how you notify the main thread. Waiting on most synchronization primitives, such as events, provide an implicit barrier, so no change would be required on your part. Polling a global variable does not provide a barrier.
If you need an explicit barrier, use Thread.MemoryBarrier.
这里不需要任何特殊处理 - 您将始终处理内存中的相同对象。
此外,由于每个线程将在数组的单独部分上工作,因此不需要锁定。
但是,如果您只进行简单的添加,则线程处理和同步回主线程的开销〜可能〜会超过获得的好处...如果您这样做,请进行分析以确保它提供净收益。
You don't need any special handling here - you'll always be working off the same objects in memory.
Also, since each thread will work on a separate portion of the array, no locking is necessary.
However, if you're only doing a simple addition, the overhead of threading and synchronizing back to the main thread ~might~ outweigh the benefits gained... If you do this, profile to make sure that it's providing a net-gain.
如果您按照建议将索引范围分解为不重叠的范围,那么只要数组是在共享内存中创建的(即不是由每个线程创建的),则不需要锁。
If you break up the index range into non-overlapping ranges as you suggested, then provided the array is created in shared memory (i.e. not by each thread), then no locks are required.
如果在修改数组完成后使用回调,可能会没问题,但如果有任何问题,使用锁将确保其他线程已释放数组。
http://msdn.microsoft.com/en-us /library/c5kehkcz(VS.71).aspx
You will probably be fine if you are using callbacks when they are done modifying the arrays, but if there is any question using a Lock will ensure the other threads have let go of the arrays.
http://msdn.microsoft.com/en-us/library/c5kehkcz(VS.71).aspx
只要您没有在主线程中复制数组,我认为您不需要执行任何操作。只需等待工作线程完成即可。
As long as you didn't make a copy of the array in the main thread, I don't think you should have to do anything. Just wait until the worker threads are finished.