How to synchronize this special case of threads with C++ std::thread

88 views Asked by At

I need some help for following case: I have a main program that starts multiple instances of the same function as threads. The function that gets called is split in at least two parts. First, every instance has to do that Part 1 of the function before they can continue with Part 2. Here I need to synchronize them. To make it easier to understandable, I will write some example code:

void TMainForm::foo(int numThreads)
{
    std::cout << "Part 1: do some work" << std::endl;

    /* HERE NEEDS TO BE SOMETHING THAT CHECKS WHETHER EVERY INSTANCE HAS DONE PART 1 !!*/

    std::cout << "Part 2: do some work" << std::endl;
}
//---------------------------------------------------------------------------

void TMainForm::StartingThreads()
{
    int threads = std::thread::hardware_concurrency();
    std::vector<std::thread> t(threads);

    for (int i = 0; i < threads; i++)
        t[i] = std::thread(foo, threads);

    for (int i = 0; i < threads; i++)
        t[i].join();
}
//--------------------------------------------------------------------------- 

I tried to use a mutex lock but it didn't work for me. I incremented a atomic variable (lets say atomic a) and if the value was smaller than numThreads I did mutex::lock. When the last instance would have done it's work, it would have done a mutex::unlock. But my threads did always stuck after Part 1.

Does anybody has some idea?

1

There are 1 answers

2
Joseph Larson On

If you're using C++ 20, then other folks have given you an answer. If you're on 17 or older, then I would make a class that you can unit test like crazy.

class Barrier {
public:
    Barrier(int dc = 1): desiredCount(dc) {}

    void done() {
        std::unique_lock<std::mutex> lock(mutex);
        ++doneCount;
        condVar.notify_all();
    }

    void waitReady() {
        std::unique_lock<std::mutex> lock(mutex);
        while (doneCount < desiredCount) {
            condVar.wait(lock);           
        }
    }

private:
    std::mutex mutex;
    std::cond_var condVar;
    int desiredCount = 1;
    int doneCount = 0;
};

Then in your code, have one of these, initialized to the thread count, then in the threads:

barrier.done();
barrier.waitReady();

I'm writing this in place -- may not be perfect code. There are other ways to use wait (you can pass a predicate), but this is the pattern I always use.