Мне тут потребовался примитив синхронизации, в чем-то похожий на добавленный в C++20 std::latch. Но с важным отличием: в `std::latch` нужно в конструкторе указывать значение счетчика. А в моем случае это количество заранее точно неизвестно.
Грубо говоря, сценарий использования `std::latch`: есть тред A, который ждет, пока N тредов B(i) сделают кусок работы. Тред A засыпает на `wait`, каждый тред B(i) рано или поздно вызывает `count_down` и когда это сделают все треды B(i), тред А проснется.
Все это отлично работает пока N известно заранее.
В моем же случае тред С создает сперва тред A, а затем начинает создавать треды B. И тред A точно не знает, сколько именно C создаст тредов B. Просто в какой-то момент треду A нужно будет дождаться пока запущенные треды B завершат свою работу. Для чего каждый тред B сперва инкрементирует счетчик, а затем декрементирует. Треду же А достаточно дождаться обнуления этого счетчика.
Сделанный для этих целей простой вариант "барьера" можно увидеть под катом.
Используется приблизительно следующим образом:
// Это все внутри треда C. meeting_room_t completion_room; std::thread thread_a{[&]() { ... // что-то делает. // Нужно дождаться пока треды B завершат свою работу. completion_room.wait_then_close(); ... // еще что-то делает. }}; // Создаем треды B. std::vector<std::thread> threads_b; while(some_condition()) { threads_b.push_back([&completion_room]() { completion_room.enter(); // Увеличили счетчик. ... // что-то делает. completion_room.leave(); // Уменьшили счетчик. }); ... // какие-то еще действия. } // Осталось дождаться завершения работы. for(auto & t : threads_b) t.join(); thread_a.join(); |
Возникла сложность с названием для такого примитива синхронизации.
Пока что у меня есть такая аналогия: комната для совещаний в офисе. В течении рабочего дня ее могут занимать для проведения совещаний, а в конце рабочего дня ее нужно закрыть. Но закрывать можно только когда в ней никого нет. Если же в комнате совещание идет, то участники могут туда заходить и выходить оттуда: пока там есть хотя бы один человек, то совещание считается незавершенным и закрывать комнату нельзя. Когда же все участники совещания комнату покинули, то считается, что совещание закончено и комнату можно закрыть.
Поэтому пока в качестве рабочего названия используется meeting_room. Однако, есть ощущение, что название не самое удачное. Вот и пытаюсь воспользоваться чужой помощью, чтобы придумать что-то получше.
Upd. Похоже, что такая штука назвается rundown: Run-Down Protection. Большое спасибо Константину за наводку.
Текущая реализация meeting_room_t: