Это невозможно с Linux futex API, и я думаю, что это также может быть доказано.
Здесь мы имеем, по сути, сценарий, в котором N процессов должен быть надежно вызван одним последним процессом, и, кроме того, ни один процесс не может касаться какой-либо общей памяти после окончательного пробуждения (поскольку она может быть уничтожена или повторно использована асинхронно). Хотя мы можем достаточно легко разбудить все процессы, основное условие гонки между пробуждением и ожиданием; если мы выдадим пробуждение до ожидания, отставший никогда не проснется.
Обычное решение для чего-то подобного состоит в том, чтобы страгглер атомарно проверял переменную состояния с ожиданием; это позволяет ему вообще не спать, если пробуждение уже произошло. Однако мы не можем сделать это здесь - как только пробуждение станет возможным, коснуться общей памяти небезопасно!
Еще один подход заключается в том, чтобы фактически проверить, все ли процессы перешли в спящий режим. Однако это невозможно с Linux futex API; единственное указание количества официантов - это возвращаемое значение из FUTEX_WAKE; если он возвращает меньше ожидаемого количества официантов, вы знаете, что некоторые еще не спали. Однако, даже если мы обнаружим, что не разбудили достаточно официантов, уже слишком поздно что-либо делать - один из процессов, которые пробудил , возможно, уже разрушил барьер!
Так что, к сожалению, этот вид немедленно уничтожаемого примитива не может быть создан с помощью Linux futex API.
Обратите внимание, что в конкретном случае одного официанта, одного вейкера, возможно, можно обойти проблему; если FUTEX_WAKE возвращает ноль, мы знаем, что на самом деле никто еще не проснулся, поэтому у вас есть шанс восстановиться. Однако сделать из этого эффективный алгоритм довольно сложно.
Сложно добавить надежное расширение к модели futex, которое бы это исправило. Основная проблема в том, что нам нужно знать, когда N потоков успешно вошли в режим ожидания, и атомно разбудить их всех. Однако любой из этих потоков может в любое время оставить ожидание для запуска обработчика сигналов - действительно, поток waker также может оставить ожидание и для обработчиков сигналов.
Однако один из возможных способов работы - это расширение модели с ключом *1018* в NT API. В случае событий с ключами потоки освобождаются от блокировки попарно; если у вас есть «release» без «wait», вызов «release» блокирует «wait».
Это само по себе недостаточно из-за проблем с обработчиками сигналов; однако, если мы позволим вызову 'release' указать количество потоков, которые будут пробуждены атомарно, это работает. У вас просто каждый поток в барьере уменьшает счетчик, а затем «ждет» события с ключом по этому адресу. Последний поток 'выпускает' N - 1 потоков. Ядро не позволяет обрабатывать любое событие wake до тех пор, пока все потоки N-1 не войдут в это ключевое состояние события; если какой-либо поток покидает вызов futex из-за сигналов (включая освобождающий поток), это вообще предотвращает любые пробуждения, пока все потоки не вернутся.