синхронизация — нужно ли синхронизировать примитивы в переполнении стека

У меня в классе изменчивый bool ‘play’, который устанавливается одним потоком и читается другим потоком.

Нужно ли синхронизировать вызовы с этим флагом? например, в этой функции:

void stop()
{
play = false;
}

В окнах они имеют _InterlockedExchange, а OSX имеет OSAtomicAdd64Barrier, я видел, как эти функции используются с общими примитивами, они мне нужны?

Спасибо

3

Решение

Зависит:

Если вы используете ЦП с моделью памяти общего порядка хранения (например, x86 / x64) или любой компьютер с только 1 ядром ЦП, то на ваш вопрос нет ответа, учитывая, что вы указали, что только 1 поток записывает флаги, и Барьерные директивы, вероятно, в любом случае оптимизированы на x86. Если вы скомпилируете тот же код на процессоре с расслабленной моделью памяти, ситуация изменится, и вы можете обнаружить, что код, который отлично работает на x86, развивает некоторые странные и трудные для воспроизведения ошибки, если вы компилируете и запускаете его на ARM или кпп например

volatile директива предотвращает кэширование записи где-либо и может означать, что поток чтения видит запись гораздо раньше, чем в volatile Директивы там не было. Если вы хотите использовать это, зависит от того, насколько важен этот интервал

1

Другие решения

Да и volatile ни в коем случае не подразумевает потокобезопасный или атомарный. использование std::mutex а также std::unique_lock и т.д., если вы можете, а не специфика платформы. std::atomic хороший выбор — может быть, даже лучший в этом случае.

3

Это зависит от того, есть ли Другой данные, которые разделяются между потоками. Проблема с потоками состоит в том, что один поток может видеть записи из другого потока в другом порядке, чем поток, в котором они были изначально созданы. В этом случае вам нужно использовать какую-то функцию _Interlocked * / Atomic или блокировки (в обоих потоках), они гарантируют, что все изменения, сделанные до того, как флаг станет видимым для другого потока.

Если нет других общих данных (или только общих данных только для чтения), или вы работаете на x86, используя просто volatile также должен работать. Однако то, что это работает, в некотором смысле только случайно, и не гарантируется никаким стандартом, поэтому, если ваша платформа поддерживает его, все равно рекомендуется использовать некоторую форму Atomic / interlocked / etc. В будущем (то есть, когда будет хорошая поддержка компилятора) вы должны использовать C ++ 11 std::atomcic как это будет переносимым между платформами.

Вы не должны использовать пустую энергонезависимую переменную, если вы сделаете это, компилятор может решить оптимизировать проверку. volatile имеет очень мало общего с кэшированием, как предлагает camelccc.

0