Считается ли изменение указателя атомарным действием в C? - PullRequest
31 голосов
/ 18 мая 2009

Если у меня есть многопоточная программа, которая читает кэш-память по ссылке. Могу ли я изменить этот указатель основным потоком, не рискуя другими потоками, читающими неожиданные значения.

Как я понимаю, если изменение является атомарным, другие потоки будут либо читать старое значение, либо новое; никогда не случайная память (или нулевые указатели), верно?

Я знаю, что мне все равно следует использовать методы синхронизации, но мне все равно любопытно.

Являются ли изменения указателя атомарными?

Обновление: моей платформой является 64-битный Linux (2.6.29), хотя я также хотел бы получить кроссплатформенный ответ:)

Ответы [ 7 ]

24 голосов
/ 18 мая 2009

Как уже упоминалось, в языке C нет ничего, что гарантировало бы это, и это зависит от вашей платформы.

На большинстве современных настольных платформ чтение / запись в выровненном месте размером с слово будет атомарным. Но это действительно не решает вашу проблему из-за переупорядочения чтения и записи процессором и компилятором.

Например, следующий код не работает:

Тема A:

DoWork();
workDone = 1;

Резьба B:

while(workDone != 0);

ReceiveResultsOfWork();

Хотя запись в workDone является атомарной, во многих системах процессор не гарантирует, что запись в workDone будет видима для других процессоров до того, как будут выполнены записи, сделанные через DoWork(). Компилятор также может свободно переупорядочить запись в workDone до перед вызовом DoWork(). В обоих случаях ReceiveResultsOfWork() может начать работать с неполными данными.

В зависимости от вашей платформы может потребоваться установка ограждений памяти и т. Д., Чтобы обеспечить правильное упорядочение. Это может быть очень сложно, чтобы получить право.

Или просто используйте замки. Гораздо проще, гораздо проще проверить, как правильно, и в большинстве случаев более чем достаточно.

12 голосов
/ 18 мая 2009

Язык C ничего не говорит о том, являются ли какие-либо операции атомарными. Я работал над микроконтроллерами с 8-битными шинами и 16-битными указателями; любая операция указателя в этих системах потенциально может быть неатомарной. Я думаю, что помню Intel 386s (некоторые из которых имели 16-битные шины), вызывающие аналогичные проблемы. Кроме того, я могу представить системы, которые имеют 64-битные процессоры, но 32-битные шины данных, что может повлечь за собой аналогичные опасения по поводу операций неатомарного указателя. (Я не проверял, существуют ли такие системы на самом деле.)

РЕДАКТИРОВАТЬ: Ответ Михаила стоит прочитать. Размер шины и размер указателя - едва ли единственное соображение относительно атомарности; это был просто первый контрпример, который пришёл мне в голову.

5 голосов
/ 18 мая 2009

Вы не упомянули платформу. Поэтому я думаю, что немного более точный вопрос будет

Гарантируются ли изменения указателя атомарными?

Различие необходимо, потому что разные реализации C / C ++ могут различаться в этом поведении. Для конкретной платформы возможно гарантировать атомарные назначения и при этом оставаться в пределах стандарта.

Относительно того, гарантировано ли это в целом в C / C ++, ответ - нет. Стандарт C не дает таких гарантий. Единственный способ гарантировать присвоение указателя является атомарным - это использовать механизм, специфичный для платформы, чтобы гарантировать атомарность назначения. Например, методы блокировки в Win32 обеспечат эту гарантию.

На какой платформе вы работаете?

4 голосов
/ 18 мая 2009

Отказ от ответа состоит в том, что спецификация C не требует, чтобы присвоение указателя было атомарным, поэтому вы не можете рассчитывать на то, что оно атомарное.

Фактическим ответом будет то, что это, вероятно, зависит от вашей платформы, компилятора и, возможно, выравнивания звезд в день, когда вы написали программу.

3 голосов
/ 18 мая 2009

«нормальная» модификация указателя не гарантируется как атомарная.

отметьте «Сравнить и поменять» (CAS) и другие элементарные операции, а не стандарт C, но большинство компиляторов имеют некоторый доступ к примитивам процессора. в случае GNU gcc существует несколько встроенных функций

1 голос
/ 18 мая 2009

Оказывается, это довольно сложный вопрос. Я задал похожий вопрос и прочитал все, на что мне указали. Я многое узнал о том, как работает кэширование в современных архитектурах, и не нашел ничего, что было бы окончательным. Как уже говорили другие, если ширина шины меньше битовой ширины указателя, у вас могут возникнуть проблемы. В частности, если данные пересекают границу строки кэша.

Благоразумная архитектура будет использовать блокировку.

1 голос
/ 18 мая 2009

Единственное, что гарантировано стандартом, это тип sig_atomic_t.

Как вы видели из других ответов, вероятно, все будет в порядке при нацеливании на общую архитектуру x86, но очень рискованно с более "специализированным" оборудованием.

Если вам действительно не терпится узнать, вы можете сравнить sizeof (sig_atomic_t) с sizeof (int *) и посмотреть, кто вы, ваша целевая система.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...