在C++中逐个同步三个线程

问题描述 投票:0回答:1

这是这个非常好的文章的延续:https://stackoverflow.com/a/33500554/22598822。该帖子适用于序列 (t1 & t2) --> t3。假设我有一个程序正在运行,并且我想在内部执行序列 t1 --> t2 --> t3 中保留三个线程(其他线程可能会或可能不会在系统上同时运行)。怎么办?

我从上面的参考文献中获取了代码,并尝试为了这个目标重新编写它,但没有成功。我的实现不正确,我将其放在这里是为了一个最小的可重现示例,也许是一个可能的起点。

标头.h:

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

MultiClass.h

#include "Header.h"
#include "SynchObj.h"

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.waitForCompletionOfT3();
            std::cout << "T1:" << i << std::endl;
            obj.signalCompletionOfT1();
        }           
    }
    void Calc2() {
        for (int i = 0; i < 10; ++i) {
            obj.waitForCompletionOfT1();
            std::cout << "T2:" << i << std::endl;
            obj.signalCompletionOfT2();
        }
    }
    void Calc3() {      
        for (int i = 0; i < 10; ++i) {
            obj.waitForCompletionOfT2();
            std::cout << "T3:" << i << std::endl;
            obj.signalCompletionOfT3();
        }       
    }
};

SynchObj.h

#include "Header.h"

class SyncObj {
    std::mutex mux;
    std::condition_variable cv;  
    bool completed[3]{ false, false, false };

public:

    /***** Original (t1 & t2) --> t3 *****/
    /*
    void signalCompetionT1T2(int id) {
        std::lock_guard<std::mutex> ul(mux);
        completed[id] = true;
        cv.notify_all();
    }
    void signalCompetionT3() {
        std::lock_guard<std::mutex> ul(mux);
        completed[0] = false;
        completed[1] = false;
        cv.notify_all();
    }
    void waitForCompetionT1T2() {
        std::unique_lock<std::mutex> ul(mux);             
        cv.wait(ul, [&]() {return completed[0] && completed[1]; });         
    }
    void waitForCompetionT3(int id) {
        std::unique_lock<std::mutex> ul(mux);         
        cv.wait(ul, [&]() {return !completed[id]; });           
    }
    */       
    /***********************************/
    
    /*** Unsuccessful attempt at t1 --> t2 --> t3 ***/

    void signalCompletionOfT1() {
        std::lock_guard<std::mutex> ul(mux);
        completed[0] = true;
        cv.notify_all();
    }

    void signalCompletionOfT2() {
        std::lock_guard<std::mutex> ul(mux);
        completed[0] = false;
        completed[1] = true;
        cv.notify_all();
    }

    void signalCompletionOfT3() {
        std::lock_guard<std::mutex> ul(mux);
        completed[0] = false;
        completed[1] = false;
        completed[2] = true;
        cv.notify_all();
    }

   void waitForCompletionOfT1() {
        std::unique_lock<std::mutex> ul(mux);             
        cv.wait(ul, [&]() {return !completed[2]; });         
    }

    void waitForCompletionOfT2() {
        std::unique_lock<std::mutex> ul(mux);             
        cv.wait(ul, [&]() {return !completed[0]; });         
    }

    void waitForCompletionOfT3() {
        std::unique_lock<std::mutex> ul(mux);         
        cv.wait(ul, [&]() {return !completed[1]; });           
    }

};

来源.cpp:

#include "Header.h"
#include "MultiClass.h"

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

可能的输出#1(所需):

T1:1
T1:2
T1:3
T1:4
T1:5
T1:6
T1:7
T1:8
T1:9
T2:0
T2:1
T2:2
T2:3
T2:4
T2:5
T2:6
T2:7
T2:8
T2:9
T3:0
T3:1
T3:2
T3:3
T3:4
T3:5
T3:6
T3:7
T3:8
T3:9

可能的输出#2:

0
T2:1
T2:2
T2:3
T2:4
T2:5
T2:6
T2:7
T2:8
T2:9
c++ multithreading conditional-variable
1个回答
0
投票

对于此应用程序,使用信号量会更直接一些。以下程序输出您可能的输出#1:

使用 g++ 12.2.1 使用命令行编译:g++ -std=c++20 -pthread MultiClass.cpp

多类.cpp

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

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:
    std::binary_semaphore t1{1};
    std::binary_semaphore t2{0};
    std::binary_semaphore t3{0};

    void Calc1() {
        t1.acquire();
        for (int i = 0; i < 10; ++i) {
            std::cout << "T1:" << i << std::endl;
        }
        t2.release();
    }
    void Calc2() {
        t2.acquire();
        for (int i = 0; i < 10; ++i) {
            std::cout << "T2:" << i << std::endl;
        }
        t3.release();
    }
    void Calc3() {
        t3.acquire();
        for (int i = 0; i < 10; ++i) {
            std::cout << "T3:" << i << std::endl;
        }
    }
};


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

顺便说一句,在您的代码中,您需要在开始完成数组时将其中一个设置为 true。

bool completed[3]{ true, false, false };

© www.soinside.com 2019 - 2024. All rights reserved.