Является ли volatile int в C таким же хорошим, как std :: atomic <int>в C ++ 0x? - PullRequest
19 голосов
/ 08 июля 2011

Мне нужно, чтобы в моей программе были атомарные переменные. Ранее я использовал std::atomic<int>, но платформа, на которой я сейчас работаю, не имеет компилятора g ++, который поддерживает C ++ 0x. Я использовал volatile int, и он, кажется, работает, так как я еще не испытывал состояния гонки в многоядерной системе, на которой я тестирую ее.

Мой вопрос: volatile int это атомное как std::atomic<int>? Кроме того, это создает барьеры памяти (который я также требую)?

Ответы [ 7 ]

28 голосов
/ 08 июля 2011

Нет. volatile не имеет ничего общего с многопоточностью. Он не устанавливает барьер памяти (хотя некоторые компиляторы могут добавить это в любом случае ) и не дает никаких гарантий относительно переупорядочения чтения / записи в отношении энергонезависимых объектов.

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

Вы также можете прочитать это

6 голосов
/ 08 июля 2011

Изменчивые переменные НЕ подразумевают барьеры памяти и не имеют операций exchange или compare_exchange_*, равных std::atomic.Они избегают компиляции нагрузки на несколько нагрузок на уровне машинного кода (и наоборот, и аналогично для магазинов), но это все.

Вас могут заинтересовать следующие статьи:

Если у вас нет std::atomicвы можете использовать boost :: atomic или использовать низкоуровневые барьерные и примитивные атомарные операции, предлагаемые любым компилятором, который вы используете.

4 голосов
/ 08 июля 2011

Я видел, как вы спрашивали о GCC в некоторых комментариях, вот, пожалуйста.

Встроенные функции GCC для доступа к атомарной памяти

1 голос
/ 08 июля 2011

volatile в основном говорит компилятору, что он не может делать предположения о том, что находится в определенной области памяти.Например,

bool test = true;
while(!test)
{
    /* do something (e.g. wait) */
}

компилятор может оптимизировать все while, поскольку он предполагает, что test всегда верно.Однако, если в какой-то момент test будет обновляться откуда-то еще (например, с некоторым оборудованием или другим потоком), мы не хотим, чтобы компилятор предполагал, что он знает, что находится в test.Мы можем сказать компилятору, что использование volatile.

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

Ps Я бесстыдно украл этот пример изгде-то, но не могу вспомнить, где я это видел.

1 голос
/ 08 июля 2011

Вот хорошее резюме различий здесь , от Херба Саттера. В итоге (вырезать и вставлять):

Для безопасного написания кода без блокировки, который общается между потоками без используя замки, предпочитаю использовать заказанные атомарные переменные: Java / .NET volatile, C ++ 0x атомарный и C-совместимый atomic_t.

Для безопасного общения с спец. аппаратное обеспечение или другая память, которая имеет необычная семантика, использование неоптимизируемое переменные: ISO C / C ++ изменчивый. Помните, что читает и пишет о эти переменные не обязательно атомный, однако.

1 голос
/ 08 июля 2011

До C ++ 0x язык не поддерживал потоки, поэтому не предотвращал множественный доступ.Объявление его изменчивым поможет некоторым, но это не помешает гонкам.

Подробнее см. http://en.wikipedia.org/wiki/Volatile_variable.

Чтобы действительно сделать операции атомарными, вам нужно использоватькакой бы механизм блокировки не создавал ваша потоковая библиотека (потоки win32, pthreads и т. д.).

0 голосов
/ 08 июля 2011

Эта ссылка выглядит хорошо ...

http://www.open -std.org / jtc1 / sc22 / wg21 / docs /apers / 2006 / n2047.html

...