Search code examples
c++multithreadingsemaphorebarrier

Sharing Barriers across objects/threads


Lets say I have Object A and Object B. ObjA creates multiple 'ObjB's and keeps a pointer to each, then detaches a thread on each object B to do work. I want to implement a barrier in ObjA that only unlocks whenever all 'ObjB's have reached a certain internal condition within their work functions.

How can I create a barrier with a dynamic count within ObjA, and then make ObjB aware of that barrier so that it can arrive at the barrier? I wanted to use std::barrier but I've had problems trying to do so.

Thus far I cannot make a std::barrier member variable in ObjA because it requires an input size which I will only know once ObjA is constructed. If I create the barrier inside of the busy function of ObjA, then any signal function that ObjB calls to A with won't have scope to it.

Is the best approach to do some homespun semaphore with busy waiting?


Solution

  • You can use a conditional variable.

        #include <iostream>
        #include <condition_variable>
        #include <thread>
        #include <vector>
         
        std::condition_variable cv;
        std::mutex cv_m; // This mutex is used for three purposes:
                         // 1) to synchronize accesses to count
                         // 3) for the condition variable cv
        int total_count = 10; // This is count of objBs
        int count = total_count;
         
         
        void obj_b_signals()
        {
            // Do something..
            bool certainCondition = true;
            // We have reached the condition..
            if (certainCondition) {
                {
                    std::lock_guard<std::mutex> lk(cv_m);
                    count--;
                }
                std::cerr << "Notifying...\n";
                cv.notify_one();
            }
        }
         
        int main()
        {
            // obj A logic
           std::vector<std::thread> threads;
           for (size_t i=0; i<total_count; ++i) {
                threads.emplace_back(std::thread(obj_b_signals));
            }
            {
                std::unique_lock<std::mutex> lk(cv_m);
                std::cerr << "Waiting for ObjBs to reach a certain condition... \n";
                cv.wait(lk, []{return count == 0;});
                std::cerr << "...finished waiting. count == 0\n";            
            }
            // Do something else
            for (std::thread & t: threads) {
                t.join();
            }
        }