Nidhoegger
Nidhoegger

Reputation: 5212

Synchronize three Threads in C++

I have the following program (made up example!):

#include<thread>
#include<mutex>
#include<iostream>

class MultiClass {
    public:
        void Run() {
            std::thread t1(&MultiClass::Calc, this);
            std::thread t2(&MultiClass::Calc, this);
            std::thread t3(&MultiClass::Calc, this);
            t1.join();
            t2.join();
            t3.join();
        }
    private:
        void Calc() {
            for (int i = 0; i < 10; ++i) {
                std::cout << i << std::endl;
            }
        }
};

int main() {
    MultiClass m;
    m.Run();
    return 0;
}

What I need is to sync the loop iterations the following way and I cant come up with a solution (I've been fiddling for about an hour now using mutexes but cant find THE combination): t1 and t2 shall do one loop iteration, then t3 shall do one iteration, then again t1 and t2 shall do one, then t3 shall do one.

So you see, I need t1 and t2 to do things simultaneously and after one iteration, t3 shall do one iteration on its own.

Can you point your finger on how I would be able to achieve that? Like I said, ive been trying this with mutexes and cant come up with a solution.

Upvotes: 0

Views: 3304

Answers (2)

MikeMB
MikeMB

Reputation: 21126

If you really want to do this by hand with the given thread structure, you could use something like this*:

class SyncObj {
    mutex mux;
    condition_variable cv;  
    bool completed[2]{ false,false };

public:
    void signalCompetionT1T2(int id) {
        lock_guard<mutex> ul(mux);
        completed[id] = true;
        cv.notify_all();
    }
    void signalCompetionT3() {
        lock_guard<mutex> ul(mux);
        completed[0] = false;
        completed[1] = false;
        cv.notify_all();
    }
    void waitForCompetionT1T2() {
        unique_lock<mutex> ul(mux);             
        cv.wait(ul, [&]() {return completed[0] && completed[1]; });         
    }
    void waitForCompetionT3(int id) {
        unique_lock<mutex> ul(mux);         
        cv.wait(ul, [&]() {return !completed[id]; });           
    }       
};

class MultiClass {
public:
    void Run() {
        std::thread t1(&MultiClass::Calc1, this);
        std::thread t2(&MultiClass::Calc2, this);
        std::thread t3(&MultiClass::Calc3, this);
        t1.join();
        t2.join();
        t3.join();
    }
private:
    SyncObj obj;
    void Calc1() {
        for (int i = 0; i < 10; ++i) {
            obj.waitForCompetionT3(0);
            std::cout << "T1:" << i << std::endl;
            obj.signalCompetionT1T2(0);
        }           
    }
    void Calc2() {
        for (int i = 0; i < 10; ++i) {
            obj.waitForCompetionT3(1);
            std::cout << "T2:" << i << std::endl;
            obj.signalCompetionT1T2(1);
        }
    }
    void Calc3() {      
        for (int i = 0; i < 10; ++i) {
            obj.waitForCompetionT1T2();
            std::cout << "T3:" << i << std::endl;
            obj.signalCompetionT3();
        }       
    }
};

However, this is only a reasonable approach, if each iteration is computational expensive, such that you can ignore the synchronization overhead. If that is not the case you should probably better have a look at a proper parallel programming library like intel's tbb or microsofts ppl.

*)NOTE: This code is untested and unoptimized. I just wrote it to show what the general structure could look like

Upvotes: 1

Nim
Nim

Reputation: 33655

Use two condition variables, here is a sketch..

thread 1 & 2 wait on condition variable segment_1:

std::condition_variable segment_1;

thread 3 waits on condition variable segment_2;

std::condition_variable segment_2;

threads 1 & 2 should wait() on segment_1, and thread 3 should wait() on segment_2. To kick off threads 1 & 2, call notify_all() on segment_1, and once they complete, call notify_one() on segment_2 to kick off thread 3. You may want to use some controlling thread to control the sequence unless you can chain (i.e. once 1 & 2 complete, the last one to complete calls notify for thread 3 and so on..)

This is not perfect (see lost wakeups)

Upvotes: 1

Related Questions