Одновременный запуск алгоритма в потоках
Разбираю задачи на многопоточность с гонкой за ресурсами. Какие есть методы одновременного старта нескольких потоков? Знаю что можно сделать через atomic. Правильно ли я использую atomic_bool и как можно сделать по другому?
std::atomic_bool ready{ false };
struct B {
void start(){
while (!ready);
// здесь алгоритм
};
};
int main() {
B b1, b2;
std::thread thread1(&B::start,b1);
std::thread thread1(&B::start, b2);
ready = true;
b1.join();
b2.join();
return 0; };
Ответы (2 шт):
В C++20 для этого есть std::latch и std::barrier. Для однократной синхронизации лучше std::latch.
Ожидание while (!ready); плохо тем, что напрасно рсходуются ресурсы процессора, которые могли бы служить потоку, выполняющему более полезную работу. В С++20 есть std::atomic::wait для ожидания на атомарной переменной. Но всё равно просто ready = true; имеет тот недостаток, что потоки могут к этому моменту не дойти до точки ожидания.
До C++20 -- да, можно сделать на condition variable, но решение будет громоздким (и слегка менее эффективным). Или обратиться к библиотекам (в boost есть barrier и latch) или к примитивам ОС (futex в linux, Event Object в Windows)
Гарантированной одновременности достичь невозможно, но задача может стоять чтобы каждый поток выполнил некую инициализацию перед выполнением дальнейшего кода.
В многопоточных программах сихронизация выполняется без бесконечных циклов. В начале был вариант использовать функции подачи сигналов другим спящим процессам, например condition.totify_all();. Но возникали неприятности из-за полного зависания программы, если подали сигнал, а клиент ещё не успел дать команду .wait(). Сигнал отправился только тем процессам, что ожидали его. И пришлось ещё сначала проверять флаг, задача готова или нет.
В Си++ позже дописали удобные инструменты именно для одноразового момента синхронизации потоков. Это promise и future. promise посылает сигнал, что задача выполнена, а future только если задача ещё не была выполнена, ожидает сигнал.
# include <atomic>
# include <future>
# include <thread>
# include <unistd.h>
std::promise<void> pready;
auto fready = pready.get_future();
//std::atomic_flag ready{ false };
struct B {
void start(){
fready.wait();
//while (!ready);
// здесь алгоритм
};
};
int main() {
B b1, b2;
std::thread thread1(&B::start,b1);
std::thread thread2(&B::start, b2);
sleep(1);
//ready = true;
pready.set_value();
thread1.join();
thread2.join();
return 0; }