Одновременный запуск алгоритма в потоках

Разбираю задачи на многопоточность с гонкой за ресурсами. Какие есть методы одновременного старта нескольких потоков? Знаю что можно сделать через 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 шт):

Автор решения: Alex Guteniev

В 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)

Гарантированной одновременности достичь невозможно, но задача может стоять чтобы каждый поток выполнил некую инициализацию перед выполнением дальнейшего кода.

→ Ссылка
Автор решения: AlexGlebe

В многопоточных программах сихронизация выполняется без бесконечных циклов. В начале был вариант использовать функции подачи сигналов другим спящим процессам, например 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;    }
→ Ссылка