У меня есть многопоточное приложение C ++, которое выполняет 3D-рендеринг с помощью библиотеки OpenSceneGraph. Я планирую запустить цикл рендеринга OSG как отдельный поток с использованием boost :: thread, передавая в поток структуру данных, содержащую общее состояние. Я стараюсь избегать чего-либо слишком тяжелого (например, мьютексов) для синхронизации, так как цикл рендеринга должен быть довольно плотным, а сам OSG пытается избежать блокировки. Большая часть общего состояния устанавливается до запуска потока и никогда не изменяется. У меня есть некоторые данные, которые нужно изменить, и я планирую использовать их в двойном буфере. Однако у меня есть простое логическое значение для подачи сигнала потоку о приостановке рендеринга, а затем возобновлении рендеринга и еще одно, чтобы его убить. В обоих случаях поток приложения устанавливает bool, а поток рендеринга только его читает. Мне нужно синхронизировать доступ к этим bools? Насколько я могу судить, хуже всего может случиться то, что цикл рендеринга продолжается на дополнительный кадр перед приостановкой или завершением.
Нужен ли мне мьютекс в многопоточном приложении C ++ для защиты простого логического значения?
Ответы (5)
В C ++ 11 и более поздних версиях, в которых есть определенная стандартами параллелизм, используйте для этой цели std::atomic<bool>
. Из http://en.cppreference.com/w/cpp/atomic/atomic:
Если один поток записывает в атомарный объект, а другой поток читает из него, поведение четко определено (подробности о гонках данных см. В модели памяти).
Следующий старый ответ мог быть верным когда-то в прошлом для некоторых компиляторов и некоторых операционных сред, но сегодня на него не следует полагаться:
Вы правы, в этом случае вам не нужно синхронизировать bools. Однако вы должны объявить их volatile
, чтобы компилятор действительно считывал их каждый раз из памяти, а не кэшировал предыдущее чтение в потоке (это упрощенное объяснение, но для этой цели оно должно работать).
В следующем вопросе содержится дополнительная информация об этом: Поток C ++, общие данные
Почему бы просто не использовать заблокированную переменную?
Что касается C ++ 11 и более поздних версий, он, наконец, поддерживает потоки и четко заявляет, что изменение bool (или другой неатомарной переменной) в одном потоке и одновременный доступ к нему в другом является неопределенным поведением. В вашем случае использования std::atomic<bool>
должно быть достаточно для исправления вашей программы, избавляя вас от использования блокировок.
Не используйте volatile
. Это не имеет ничего общего с потоками. Для получения дополнительной информации см. Могу ли я прочитать bool переменная в потоке без мьютекса?
Я не думаю, что вам здесь нужен полноценный мьютекс - хотя поток рендеринга должен будет ждать в «приостановленном» состоянии, если вы не используете объект синхронизации, поддерживающий примитив ожидания. .
Однако вам следует изучить использование различных примитивов взаимоблокированного обмена (InterlockedExchange под Windows). Не потому, что чтение / запись из bool не атомарны, а чтобы гарантировать отсутствие странного поведения, компилятор переупорядочивает доступ к памяти в одном потоке.
В этом потоке есть немного больше информации и обсуждение безопасности потоков, особенно для простых типов данных:
Как создать потокобезопасный одноэлементный шаблон в Windows?