C++ энергозависимые переменные многопоточности

Я пишу приложение C++.

У меня есть переменная класса, в которую пишет больше чем один поток.

В C++, что-нибудь, что может быть изменено без компилятора, "поняв", что он изменяется потребности, которые будут отмечены энергозависимое право? Таким образом, если мой код многопоточен, и один поток может записать в var, в то время как другой читает из него, я должен отметить var volaltile?

[У меня нет состояния состязания, так как я полагаюсь на записи к ints тому, чтобы быть атомарным]

Спасибо!

6
задан quamrana 27 February 2010 в 17:26
поделиться

6 ответов

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

Если вы действительно хотите сделать это, вы могли бы посмотреть на stacktrace, но поскольку вы все равно меняете свою программу для этого, вы можете также ввести новое статическое логическое поле isUnitTesting в свой код, и JUnit установить это значение true. Оставь это простым.

-121--1039871-

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

Он может быть использован для указания компилятору не предполагать, что после считывания из памяти значение не изменится:

while (*p)
{
  // ...
}

В приведенном выше коде, если * p не записано в пределах цикла, компилятор может принять решение о перемещении чтения за пределы цикла, более следующим образом:

cached_p=*p
while (cached_p)
{
  // ...
}

Если p является указателем на порт ввода/вывода, подключенный к памяти, то перед каждым вводом цикла требуется первая версия, в которой порт проверяется.

Если p является указателем на память в многопоточном приложении, вам по-прежнему не гарантируется атомарность операций записи.

1
ответ дан 8 December 2019 в 13:45
поделиться

volatile предписывает компилятору не выполнять оптимизацию на основе «интуиции» значения или использования переменной, поскольку ее можно оптимизировать «извне». Однако

volatile не обеспечивает никакой синхронизации, и ваше предположение о том, что запись в int является атомарной, практически нереально!

Я предполагаю, что нам нужно увидеть какое-то использование, чтобы узнать, нужен ли volatile в вашем случае (или проверить поведение вашей программы) или, что более важно, если вы видите какую-то синхронизацию.

3
ответ дан 8 December 2019 в 13:45
поделиться

Без блокировки вы все равно можете получить «невозможное» изменение порядка, выполненное компилятором или процессором. И нет никакой гарантии, что запись в int является атомарной.

Было бы лучше использовать правильную блокировку.

0
ответ дан 8 December 2019 в 13:45
поделиться

Volatile решит вашу проблему, т.е. это гарантирует согласованность всех кешей системы. Однако это будет неэффективно, поскольку будет обновлять переменную в памяти при каждом доступе R или W. Вы можете подумать об использовании барьера памяти только тогда, когда это необходимо. Если вы работаете с gcc / icc, обратите внимание на встроенные средства синхронизации: http://gcc.gnu.org/onlinedocs/gcc-4.1.2/gcc/Atomic-Builtins.html

РЕДАКТИРОВАТЬ (в основном о комментарии pm100): Я понимаю, что мои убеждения не являются справочными, поэтому я нашел кое-что, что можно процитировать :)

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

Из Dr Dobb's

Более интересно:

Неустойчивые поля линеаризуемы. Чтение изменчивого поля похоже на получение блокировки; рабочая память становится недействительной, и текущее значение изменчивого поля повторно считывается из памяти. Запись изменчивого поля похожа на снятие блокировки: изменчивое поле немедленно записывается обратно в память. (все дело в согласованности, а не в атомарности)

из Искусство многопроцессорного программирования , Морис Херлихи и Нир Шавит

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

{{ 1}}
-4
ответ дан 8 December 2019 в 13:45
поделиться

В C++ пока нет никаких возможностей для многопоточности. На практике volatile не делает того, что вы имеете в виду (он был разработан для аппаратных средств с поддержкой памяти, и хотя эти две проблемы похожи, они достаточно различны, чтобы volatile не делал то, что нужно - обратите внимание, что volatile использовался в других языках для использования в контексте mt).

Так что если вы хотите записать объект в одном потоке и прочитать его в другом, вам придется использовать функции синхронизации, которые нужны вашей реализации, когда они ей нужны. Для тех, о которых я знаю, volatile не играет никакой роли в этом.

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

13
ответ дан 8 December 2019 в 13:45
поделиться

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

Однако это не очень сильный контракт на современные многоядерные процессоры. Volatile не обещает , а не , что другой поток, работающий на другом ядре, может видеть обновления переменной. Для этого требуется барьер памяти, обычно это инструкция, очищающая кеш-память ЦП. Если вы не установите барьер, поток будет продолжать работать до тех пор, пока такой сброс не произойдет естественным образом. В конечном итоге это произойдет, планировщик потоков обязательно предоставит его. Это может занять миллисекунды.

Как только вы позаботитесь о подобных деталях, вы в конечном итоге заново изобрели переменную условия (также известную как событие), которая вряд ли будет быстрее, чем та, которая предоставляется библиотекой потоковой передачи. Или также проверено. Не изобретайте свои собственные, многопоточность достаточно сложна, чтобы разобраться, вам не нужен FUD, чтобы не быть уверенным в надежности основных примитивов.

4
ответ дан 8 December 2019 в 13:45
поделиться
Другие вопросы по тегам:

Похожие вопросы: