Прежде всего, я знаю, что это может быть реализовано с помощью мьютекса и условной переменной, но я хочу максимально эффективную реализацию.
Я хотел бы семафор с быстрым путем, когда нет спора. В Linux это легко с помощью futex; например, вот ожидание:
if (AtomicDecremenIfPositive(_counter) > 0) return; // Uncontended
AtomicAdd(&_waiters, 1);
do
{
if (syscall(SYS_futex, &_counter, FUTEX_WAIT_PRIVATE, 0, nullptr, nullptr, 0) == -1) // Sleep
{
AtomicAdd(&_waiters, -1);
throw std::runtime_error("Failed to wait for futex");
}
}
while (AtomicDecrementIfPositive(_counter) <= 0);
AtomicAdd(&_waiters, -1);
и сообщение:
AtomicAdd(&_counter, 1);
if (Load(_waiters) > 0 && syscall(SYS_futex, &_counter, FUTEX_WAKE_PRIVATE, 1, nullptr, nullptr, 0) == -1) throw std::runtime_error("Failed to wake futex"); // Wake one
Сначала я подумал, что для Windows нужно просто использовать NtWaitForKeyedEvent (). Проблема в том, что это не прямая подстановка, поскольку она не проверяет атомарно значение в _counter перед входом в ядро, и поэтому может пропустить пробуждение из NtReleaseKeyedEvent (). Хуже того, тогда NtReleaseKeyedEvent () заблокируется.
Какое лучшее решение?