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

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

Ответы

Ответ 1

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

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


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

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

Следующий вопрос содержит дополнительную информацию об этом: С++ Thread, общие данные

Ответ 3

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

Ответ 4

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

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