Нужен ли мне мьютекс в многопоточном приложении C ++ для защиты простого логического значения?

У меня есть многопоточное приложение C ++, которое выполняет 3D-рендеринг с помощью библиотеки OpenSceneGraph. Я планирую запустить цикл рендеринга OSG как отдельный поток с использованием boost :: thread, передавая в поток структуру данных, содержащую общее состояние. Я стараюсь избегать чего-либо слишком тяжелого (например, мьютексов) для синхронизации, так как цикл рендеринга должен быть довольно плотным, а сам OSG пытается избежать блокировки. Большая часть общего состояния устанавливается до запуска потока и никогда не изменяется. У меня есть некоторые данные, которые нужно изменить, и я планирую использовать их в двойном буфере. Однако у меня есть простое логическое значение для подачи сигнала потоку о приостановке рендеринга, а затем возобновлении рендеринга и еще одно, чтобы его убить. В обоих случаях поток приложения устанавливает bool, а поток рендеринга только его читает. Мне нужно синхронизировать доступ к этим bools? Насколько я могу судить, хуже всего может случиться то, что цикл рендеринга продолжается на дополнительный кадр перед приостановкой или завершением.


person Brian Stewart    schedule 21.10.2008    source источник


Ответы (5)


В C ++ 11 и более поздних версиях, в которых есть определенная стандартами параллелизм, используйте для этой цели std::atomic<bool>. Из http://en.cppreference.com/w/cpp/atomic/atomic:

Если один поток записывает в атомарный объект, а другой поток читает из него, поведение четко определено (подробности о гонках данных см. В модели памяти).


Следующий старый ответ мог быть верным когда-то в прошлом для некоторых компиляторов и некоторых операционных сред, но сегодня на него не следует полагаться:

Вы правы, в этом случае вам не нужно синхронизировать bools. Однако вы должны объявить их volatile, чтобы компилятор действительно считывал их каждый раз из памяти, а не кэшировал предыдущее чтение в потоке (это упрощенное объяснение, но для этой цели оно должно работать).

В следующем вопросе содержится дополнительная информация об этом: Поток C ++, общие данные

person Greg Hewgill    schedule 21.10.2008
comment
Однако, согласно спецификации, «volatile» не делает этого. MSVC немного более снисходителен к ленивым программистам, но GCC, безусловно, с радостью оптимизирует, перепланирует и иным образом испортит ваши «изменчивые» обращения к памяти. - person ephemient; 21.10.2008
comment
IIRC, согласно спецификации, «изменчивый» означает, что компилятор должен предполагать, что переменная может измениться в любое время вне контроля приложения. Так что, если компилятор правильный, volatile должен дать желаемый эффект. - person Nick; 21.10.2008
comment
Нет, «энергозависимый» имеет значение только для памяти, отображаемой в регистры ввода-вывода устройства. Все остальное не указано и не выполняется GCC с более высокой оптимизацией. - person ephemient; 22.10.2008
comment
Я понимаю, что соответствующие реализации C ++ должны переоценивать изменчивые переменные после любой точки последовательности, что накладывает очень конкретные ограничения на компилятор. Тем не менее, GCC, безусловно, может не быть совместимым компилятором для C ++, и / или мое понимание может быть неправильным. - person Nick; 22.10.2008
comment
Это правда, но бесполезно. Доступ к изменчивому объекту должен быть оценен, но C ++ не может ничего сказать о том, видна ли вашему потоку запись из другого потока, потому что C ++ не может ничего сказать о потоках. Вы должны проконсультироваться с документацией к вашему компилятору / потоку или использовать C ++ 0x. - person Steve Jessop; 22.10.2008
comment
Так, например, спецификация C ++ не требует, чтобы в системах с некогерентным кешем изменчивые обращения вызывали синхронизацию кеша, только чтобы доступ (к кешу) не перемещался через точку последовательности. Компиляторы могут быть дружелюбными и выполнять синхронизацию кеша при непостоянном доступе. А может и нет. - person Steve Jessop; 22.10.2008
comment
volatile не предотвращает изменение порядка чтения / записи. VC ++ 2005/8, похоже, делает это правильно, добавляя дополнительное значение ключевому слову volatile так же, как это делает Java 5. GCC, с другой стороны, определенно изменит порядок вещей. - person computinglife; 22.10.2008
comment
На сегодняшний день, 2017 г. (9 лет спустя). Этот ответ является совершенно неверным. Точнее, ошибался с 2011 года. - person WhiZTiM; 18.12.2017
comment
@WhiZTiM: Спасибо, что указали на это, я обновил ответ. - person Greg Hewgill; 18.12.2017

Почему бы просто не использовать заблокированную переменную?

person shoosh    schedule 21.10.2008
comment
Нет ли накладных расходов на их использование? - person Sergio Basurco; 16.07.2015
comment
Тогда лучше использовать обычный bool, так проще и быстрее. - person Sergio Basurco; 16.07.2015

Что касается C ++ 11 и более поздних версий, он, наконец, поддерживает потоки и четко заявляет, что изменение bool (или другой неатомарной переменной) в одном потоке и одновременный доступ к нему в другом является неопределенным поведением. В вашем случае использования std::atomic<bool> должно быть достаточно для исправления вашей программы, избавляя вас от использования блокировок.
Не используйте volatile. Это не имеет ничего общего с потоками. Для получения дополнительной информации см. Могу ли я прочитать bool переменная в потоке без мьютекса?

person Tadeusz Kopec    schedule 18.12.2017

Я не думаю, что вам здесь нужен полноценный мьютекс - хотя поток рендеринга должен будет ждать в «приостановленном» состоянии, если вы не используете объект синхронизации, поддерживающий примитив ожидания. .

Однако вам следует изучить использование различных примитивов взаимоблокированного обмена (InterlockedExchange под Windows). Не потому, что чтение / запись из bool не атомарны, а чтобы гарантировать отсутствие странного поведения, компилятор переупорядочивает доступ к памяти в одном потоке.

person Rob Walker    schedule 21.10.2008

В этом потоке есть немного больше информации и обсуждение безопасности потоков, особенно для простых типов данных:

Как создать потокобезопасный одноэлементный шаблон в Windows?

person Mark Ingram    schedule 21.10.2008