Использование летучих как атомных - PullRequest
4 голосов
/ 26 июня 2010

Если у меня что-то подобное ...

volatile long something_global = 0;

long some_public_func()
{
    return something_global++;
}

Разумно ли ожидать, что этот код не сломается (состояние гонки) при доступе из нескольких потоков? Если это не стандарт, может ли это быть разумным предположением о современных компиляторах?

ПРИМЕЧАНИЕ: ВСЕ, что я использую для этого, это атомный прирост и декремент - ничего более причудливого.

Ответы [ 6 ]

16 голосов
/ 26 июня 2010

Нет - энергозависимый не означает синхронизированный.Это просто означает, что каждый доступ будет возвращать самое актуальное значение (в отличие от копии, кэшированной локально в потоке).

Постинкремент - это не атомарная операция, а доступ к памятипо памяти пишу.Чередование двух может означать, что значение фактически увеличивается только один раз.

4 голосов
/ 26 июня 2010

Нет, вы должны использовать платформо-зависимый атомарный доступ.Есть несколько библиотек, которые абстрагируют их - GLib предоставляет переносимые атомарные операции, которые при необходимости возвращаются к блокировкам мьютекса, и я считаю, что Boost также предоставляет переносимые атомы.Выученный , для действительно атомарного доступа вам необходим полный барьер памяти, который volatile не обеспечивает.Все непостоянные гарантии состоят в том, что память будет перечитываться при каждом доступе и что доступ к памяти volatile не будет переупорядочен.Оптимизатор может переупорядочить некоторый энергонезависимый доступ до или после энергозависимого чтения / записи - возможно, в середине вашего приращения!- поэтому вы должны использовать фактические атомарные операции.

3 голосов
/ 26 июня 2010

Windows предоставляет InterlockedIncrement InterlockedDecrement ) для выполнения того, что вы просите.

3 голосов
/ 26 июня 2010

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

Таким образом, компиляторы не будут выдавать атомарные инструкции только потому, что вы добавили ключевое слово volatile. Вам нужно прибегнуть к встроенной сборке или специфичным для компилятора расширениям (например, gcc atomic builtins ).

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

1 голос
/ 26 июня 2010

Volatile просто предотвращает оптимизацию, но атомарность требует большего. В x86 инструкциям должен предшествовать префикс LOCK, в MIPS цикл RMW должен быть окружен конструкцией LL / SC, ...

0 голосов
/ 26 июня 2010

Ваша проблема в том, что C не гарантирует атомарность операторов приращения, и на практике они часто не будут атомарными. Для этого вы должны использовать библиотеку, такую ​​как Windows API или встроенные функции компилятора ( GCC , MSVC ).

...