Search code examples
c++barrier

Any way to create a barrier object if number of threads are unknown until runtime?


The few examples I've seen for std:barrier statically set the expected count.

std::barrier my_barrier(5);

The code I'm writing determines the number of threads to launch based on some factors at runtime. I'm struggling to come up with a clever way to construct the barrier at runtime after the number of threads to be launched is determined. Ideas appreciated.


Solution

  • Based on your comment:

    If it's calculated it needs to be at a non-global scope. I don't see how to pass it as a local into the threads.

    At some point the barrier has to be somewhat 'global'. Sure it doesn't make sense to put the barrier globally at e.g. file scope (deleted copy ctor and assignment operator) but it does make sense to put the barrier into the scope where the (dynamic amount of) workers will be invoked. Then the barrier has to be made local to the thread function. There are multiple ways to do that, it all depends whether you're using a lambda, function object or a function. So either via capture (lambda), as a class member (function object) or as argument (all).

    e.g.

    void invoke(int num_threads)
    {
        //completition function, will be invoked after all threads arrived at the barrier
        auto on_completion = []() noexcept
        {
            std::cout << "done\n";
        };
    
        //construct barrier
        std::barrier sync_point(num_threads, on_completion);
    
        //work function (could be also a function object or a function, here we use a lambda)
        auto work = [&sync_point /*either capture*/](/*or as argument*/)
        {
            //do something, then
            //wait for all threads to arrive
            sync_point.arrive_and_wait();
        };
    
        //construct workers
        std::vector<std::jthread> threads;    //dynamic array of threads
        threads.reserve(num_threads);         //alloc space
        for (int n=0; n < num_threads; ++n) { //for each thread in list
            //invoke the work function
            threads.emplace_back(work /*, pass the function arguments here*/);
        }
    }
    

    then

    int main()
    {
        int n = 4;
        invoke(n);
    }