Оператор + = не является атомарным, то есть сначала он читает, затем записывает новое значение. Между тем, между чтением и записью поток A может переключиться на другой B, фактически без записи значения ... тогда другой поток B не увидит новое значение, поскольку оно не было назначено другим потоком A ... и при возврате к потоку A он отбросит всю работу потока B.
жный дубликат:
Синхронизация потоков. Как именно блокировка делает доступ к памяти «правильным»?
Этот вопрос вдохновленэтот.
Мы получили следующий тестовый класс
class Test
{
private static object ms_Lock=new object();
private static int ms_Sum = 0;
public static void Main ()
{
Parallel.Invoke(HalfJob, HalfJob);
Console.WriteLine(ms_Sum);
Console.ReadLine();
}
private static void HalfJob()
{
for (int i = 0; i < 50000000; i++) {
lock(ms_Lock) { }// empty lock
ms_Sum += 1;
}
}
}
Фактический результат очень близок к ожидаемому значению 100 000 000 (50 000 000 x 2, так как 2 цикла работают одновременно), с разницей в 600–200 (ошибка на моей машине составляет около 0,0004%, что очень мало). Никакой другой способ синхронизации не может обеспечить такой способ приближения (это либо гораздо большая ошибка%, либо его 100% правильность)
В настоящее время мы понимаем, что такой уровень точности обусловлен тем, что программа выполняется следующим образом:
Время идет слева направо, и 2 потока представлены двумя рядами.
где
черный ящик представляет процесс приобретения, удержания и выпуска
Блокировка плюс представляет операцию сложения (схема представляет масштаб на моем ПК, блокировка занимает примерно в 20 раз больше, чем добавить)
белый ящик представляет период, который состоит из попытки получить блокировку и дальнейшего ожидания ее появленияТакже блокировка обеспечивает полную память забора.
Таким образом, теперь возникает вопрос: если вышеуказанная схема представляет собой то, что происходит, что является причиной такой большой ошибки (теперь ее схема с большой причиной выглядит как очень сильная схема синхронизации)? Мы могли бы понять разницу между 1-10 на границах, но это явно не единственная причина ошибки? Мы не можем видеть, когда запись в ms_Sum может происходить одновременно, чтобы вызвать ошибку.
РЕДАКТИРОВАТЬ: многим нравится делать быстрые выводы. Я знаю, что такое синхронизация, и что приведенная выше конструкция не является реальным или близким к хорошему способу синхронизации потоков, если нам нужен правильный результат. Имейте некоторую веру в постер или возможно прочитайте связанный ответ сначала. Мне не нужен способ синхронизации 2 потоков для параллельного выполнения дополнений, я исследую этот экстравагантный и все же эффективный по сравнению сЛюбые возможно иприближенный альтернатива, конструкция синхронизации (она синхронизирует до некоторой степени, поэтому еене бессмысленно вроде бы предложил)