std::atomic<T> и std::condition_variable оба имеют функции-члены wait и notify_one. В некоторых приложениях у программистов может быть выбор между использованием любого из них для целей синхронизации. Одна из целей этих wait функций заключается в том, что они должны координировать свои действия с операционной системой, чтобы свести к минимуму ложные пробуждения. То есть операционная система должна избегать пробуждения wait-ing thread до тех пор, пока не будут вызваны notify_one или notify_all.
На моей машине sizeof(std::atomic<T>) — это sizeof(T), а sizeof(std::condition_variable) — это 72. Если вы исключите член std::atomic<T>T, то std::condition_variable резервирует 72 байта для целей синхронизации, а sizeof(std::atomic<T>) резервирует 0 байтов.
Мой вопрос: следует ли ожидать различного поведения между функциями std::condition_variable и std::atomic<T>wait? Например, должно ли std::condition_variable иметь меньше ложных пробуждений?
Если поток, который вызывает ожидание, не проверяет, изменилась ли атомарная переменная, какой поток это делает?
что вы подразумеваете под «не проверяет, изменилась ли атомарная переменная»? Весь смысл ожидания в том, чтобы проверить, изменилась ли переменная
Вы сказали: «Поэтому 'atomic' вообще не требует переключения потоков для получения мьютекса». Я понял это так: «Вы можете подумать, что когда atomic проверяет, изменился ли его T, ваш процессор должен переключиться на вызывающий поток. Однако, поскольку «atomic не понадобится такая защита для проверки состояния ожидания», переключение потоков ненужно. Другое поток может проверить, изменились ли атомарные T, и если да, то разбудить вызывающий поток». Это имеет смысл для меня. Тогда я предполагаю, что какой-то процесс ОС отвечает за проверку того, изменились ли атомы T (для ВСЕХ атомов, ожидающих в настоящее время).
Ага, неудачная формулировка... Тогда поправлюсь. cv.wait() освобождает мьютекс, когда засыпает, и снова блокирует его, когда просыпается из-за уведомления. Если мьютекс заблокирован другим потоком, поток, удерживающий cv, снова перейдет в спящий режим до тех пор, пока другой поток не освободит мьютекс. Как только cv получит мьютекс, он может проверить условие ожидания. Atomic не нуждается в мьютексе и потенциально может вызвать меньшее переключение контекста потока.





My question: should I expect different behavior between
std::condition_variable's andstd::atomic<T>'swaitfunctions? For example, shouldstd::condition_variablehave fewer spurious wakeups?
std::atomic::wait не имеет ложных пробуждений. Стандарт гарантирует, что было замечено измененное значение, в [atomics.types.generic.general]/30 написано:
Effects: Repeatedly performs the following steps, in order:
(30.1) Evaluates load(order) and compares its value representation for equality against that of old.
(30.2) If they compare unequal, returns.
(30.3) Blocks until it is unblocked by an atomic notifying operation or is unblocked spuriously.
Итак, если базовая реализация атомарного ожидания вызывает ложные пробуждения, они скрыты реализацией стандартной библиотеки C++..
Если ваши вопросы касаются того, есть ли больше или меньше ложных пробуждений в атомарных или условных переменных основная реализация, то это зависит от реализации. Будет зависеть от операционной системы и реализации библиотеки. Наиболее вероятный ответ: нет, потому что окончательная реализация, в которой ОС вызывает ядро, скорее всего, будет такой же.
condition_variableбудет брать мьютекс при каждом пробуждении, чтобы проверить условие ожидания, и освобождать его при возвращении в ожидание. Блокировка/освобождение мьютекса - это служебный вызов ОС (хорошо зависит от реализации, но обычно так и есть). Я ожидаю, что «атомарному» не понадобится такая защита для проверки состояния ожидания. Таким образом, «атомарному» вообще не нужно переключение потоков для получения мьютекса.