Скажем, у меня есть два массива:
int[] array1 = new int[2000000];
int[] array2 = new int[2000000];
Я засовываю некоторые значения в массивы и затем хочу добавить содержание array2 к array1 как так:
for(int i = 0; i < 2000000; ++i) array1[i] += array2[i];
Теперь, скажем, я хочу сделать обработку быстрее на многопроцессорной машине, таким образом, вместо того, чтобы просто делать цикл как вышеупомянутый, я создаю два потока. Один из которых я имею, обрабатывают первые 1 000 000 элементов в массиве, другой я имею, обрабатывают последние 1 000 000 элементов в массиве. Мой основной поток ожидает тех двух потоков, чтобы уведомить его, что они закончены, и затем продолжает использовать значения от array1 для всех видов важного материала. (Обратите внимание, что эти два рабочих потока не могут быть завершены и могут быть снова использованы, но основной поток не возобновится, пока они оба не уведомили его, чтобы сделать так.)
Так, мой вопрос: Как я могу быть уверен, что основной поток будет видеть модификации, которые эти два рабочих потока сделали к массиву? Я могу рассчитывать на это для случая, или сделать я должен пройти некоторую специальную процедуру, чтобы удостовериться, что рабочие потоки сбрасывают свои записи к массиву, и основной поток отбрасывает свои значения кэшированного массива?
Вам нужен барьер памяти для того, чтобы записи рабочего потока в массив были видны главному потоку в том порядке, который вы ожидаете.
Нужен ли вам явный барьер памяти или нет, зависит от того, как вы уведомляете главный поток. Ожидание большинства примитивов синхронизации, таких как события, обеспечивает неявный барьер, поэтому никаких изменений с вашей стороны не потребуется. Опрос глобальной переменной не обеспечивает барьера.
Если вам нужен явный барьер, используйте Thread.MemoryBarrier.
Если вам повезет и у вас есть возможность использовать .NET 4.0, вы можете просто написать:
Parallel.For(0, 2000000, i => { array1[i] += array2[i]; });
Вам не нужна явная блокировка или синхронизация, потому что:
for
) влияет на непересекающуюся часть массива Parallel.For
ожидает завершения всех задач, прежде чем вернуться, поэтому будет быть неявным барьером памяти. Как я могу быть уверен, что основной поток увидит изменения, внесенные двумя рабочими потоками в массив? Могу ли я рассчитывать на то, что это произойдет, или мне нужно пройти специальную процедуру, чтобы убедиться, что рабочие потоки сбрасывают свои записи в массив, а основной поток отбрасывает свои кэшированные значения массива?
Вам не нужна особая обработка здесь - вы всегда будете работать с одними и теми же объектами в памяти.
Кроме того, поскольку каждый поток будет работать с отдельной частью массива, блокировка не требуется.
Однако, если вы делаете только простое добавление, накладные расходы на потоки и синхронизацию с основным потоком ~ могут ~ перевесить получаемые преимущества ... Если вы сделаете это, профилируйте, чтобы убедиться, что он предоставляет сеть -прирост.
Вероятно, все будет в порядке, если вы используете обратные вызовы, когда они закончат изменять массивы, но если возникнут вопросы, использование блокировки позволит убедиться, что другие потоки отпустили массивы.
lock (array1)
{
}
http://msdn.microsoft.com/en-us/library/c5kehkcz(VS.71).aspx
Пока вы не сделали копию массива в основном потоке, я не думаю, что вам нужно что-то делать. Просто подождите, пока не закончатся рабочие потоки.
Если вы разбиваете диапазон индекса в неперекрывающиеся диапазоны, как вы предложили, тогда при условии, что массив создается в общей памяти (то есть не каждым потоком), тогда блокировки не требуются.