Модель памяти C++ и условия гонки на массивах символов
В основном у меня проблемы с пониманием этого: (из Bjarne FAQ)
Тем не менее, большинство современных процессоров не могут читать или записывать один символ, они должны читать или писать целое слово, поэтому присваивание c на самом деле является "чтением слова, содержащего c, заменой части c и повторной записью слова". "Поскольку присваивание b схоже, у двух потоков есть много возможностей для того, чтобы засорять друг друга, даже если потоки (в соответствии с их исходным текстом) не обмениваются данными!
Так как же могут существовать массивы char без 3(7?) Байтов между элементами?
2 ответа
Я думаю, что Бьярне ошибается в этом, или, по крайней мере, он значительно упрощает вещи. Большинство современных процессоров способны записывать байт, не прочитав сначала полное слово, или, скорее, они ведут себя "как будто", как это было. В частности, если у вас есть char array[2];
и поток один только доступ array[0]
и нить два только доступ array[1]
(в том числе, когда оба потока изменяют значение), тогда вам не требуется дополнительная синхронизация; это гарантировано стандартом. Если оборудование не позволяет этого напрямую, компилятор должен будет добавить саму синхронизацию.
Очень важно отметить "как будто" выше. Современное оборудование обеспечивает доступ к основной памяти по строкам кэша, а не по байту. Но в нем также есть условия для изменения отдельных байтов в строке кэша, чтобы при обратной записи ядро процессора не модифицировало байты, которые не были изменены в его кэше.
Платформа, поддерживающая C++11, должна иметь доступ к хранилищу размером один char
не придумывая пишет. x86 действительно имеет такую возможность. Если процессор должен изменять 32 бита за раз в любое время, он должен иметь 32-битную ширину char
,
(Некоторые исходные соображения: массивы хранятся смежно, а символы не имеют отступов (3.9.1).)