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