C++ Boost线程条件变量三线程

C++ Boost线程条件变量三线程,c++,boost,C++,Boost,我有一个main设置两个变量的值,并等待两个线程打印该值。然后更新值等等 对于主线程和一个线程,它可以工作,但对于两个线程则不行。 这是我的代码: void t(int id){ bool block_me = true; while(1) { { boost::mutex::scoped_lock lock(m); while(!start_t || thread_executed > 0)

我有一个main设置两个变量的值,并等待两个线程打印该值。然后更新值等等

对于主线程和一个线程,它可以工作,但对于两个线程则不行。 这是我的代码:

void t(int id){

    bool block_me = true;
    while(1)
    {
        {
            boost::mutex::scoped_lock lock(m);
            while(!start_t || thread_executed > 0)
                start_thread.wait(lock);
        }

        // Print myself
        cout<<id<<endl;

        {
            boost::mutex::scoped_lock lock(m);
            thread_executed++;
            if(thread_executed == 2){
                start_main.notify_one();
            }
        }       
    }
}

int main(){

    thread_executed = 0;
    start_t = false;

    boost::thread t1(boost::bind(&t, 1));
    boost::thread t2(boost::bind(&t, 2));

    for(int i = 1; i < 10; i++){
        cout<<"i = "<<i<<endl;
        {
            boost::mutex::scoped_lock lock(m);  
            start_t = true;
            thread_executed = 0;
            start_thread.notify_all();  

            while(thread_executed != 2){
                start_main.wait(lock);
            }
            start_t = false;
            thread_executed = 0;
            start_thread.notify_all();
        }       
    }
    return 0;
}
void t(int-id){
bool block_me=true;
而(1)
{
{
boost::mutex::作用域锁定(m);
而(!start_t| | thread_executed>0)
启动线程。等待(锁定);
}
//打印我自己

cout这里最可能发生的情况是,第一个线程运行并更改变量“published”,然后坐着等待,第二个线程只是坐着等待published再次变为0,但情况永远不会是这样,因为主线程正在等待它变为2以将其变回0

为了以有效的方式实施,可以做的事情很少:

  • 让线程将您需要打印的内容排队,然后另一个线程将从队列中取出并打印它们(或将它们写入磁盘,或任何您真正需要使用它们的操作)。这是一种非常常见的模式,可以简化总体实施。可能会有成本,然后您可能无法以这种方式实施

  • 将“状态”添加到线程中,这样当您处于“打印”状态时,线程将被唤醒并打印值;当您处于“处理”状态时,线程将在条件变量中等待,主线程将“处理”值。在更改状态之前,您可以使用等待,直到所有互斥体完成其工作

  • 有几点建议:

    • 如果在线程中读取变量“published”和“termiante_thread”,则不要在互斥保护之外更改变量。例如,当您更改变量以停止线程时,需要保护变量“published”和“termiante_thread”

    • 不要使用睡眠,您不需要它们来实现一个工作示例,它们是实现中出现问题的征兆


    我修改了我的原始代码…嗯,排队等待

    让我们来演示一下

    我稍微概括了一下,因为基本上有两个带有共享条件变量的单元素队列

    更容易推理的是两个具有不同条件和锁的独立队列。这会立即解开它们以进行同步,如果将容量定义为>1,则在主线程需要减速之前,工作线程可能会有多个积压的项目排队

    #include <thread>
    #include <queue>
    #include <mutex>
    #include <condition_variable>
    #include <iostream>
    
    static constexpr size_t queue_capacity = 1;
    
    struct Processor {
    
        Processor(int id) : id_(id) {}
    
        void work() {
            while (running) {
                int value;
                {   // pop under lock
                    std::unique_lock<std::mutex> lk(mx_);
                    cv_.wait(lk, [this] { return !running || !queue_.empty(); });
    
                    if (!running)
                        break;
    
                    // invariant: queue cannot be empty here
                    value = queue_.front();
                    queue_.pop();
                    cv_.notify_one();
                }
                std::cout << "work " << id_ << ": " << value << "\n";
            }
        }
    
        void enqueue(int value) {
            std::unique_lock<std::mutex> lk(mx_);
            cv_.wait(lk, [this] { return !running || queue_.size() < queue_capacity; });
    
            if (running) {
                queue_.push(value);
                cv_.notify_one();
            }
        }
    
        ~Processor() {
            {
                std::unique_lock<std::mutex> lk(mx_);
                cv_.notify_one();
                running = false;
            }
            if (th_.joinable())
                th_.join();
        }
    private:
        bool running = true;
        std::mutex mx_;
        std::condition_variable cv_;
        std::thread th_ {std::bind(&Processor::work, this)};
        int id_;
    
        std::queue<int> queue_;
    };
    
    int main() {
        Processor w1(1), w2(2);
    
        for (int i = 1; i < 10; ++i)
        {
            w1.enqueue(i*10);
            w2.enqueue(i*20);
    
            std::this_thread::sleep_for(std::chrono::milliseconds(150));
        }
    
        std::this_thread::sleep_for(std::chrono::seconds(4));
    }
    

    如果要向生产者发回信号,则需要第二个条件变量。此外,access*仅在锁下访问所有共享变量(您违反了该左和右键)看起来像是在寻找一个我不知道的…我需要线程启动simpe打印的条件和main更改“一”和“二”"…你考虑过使用消息队列吗?我已经修改了我的原始代码…嗯,队列为??我已经修改了我的原始代码…但是,没有使用boost barrier的解决方案吗?是的,使用barrier只是一种方法,你可以看看给出的答案之一,它显示了如何使用队列来完成任务,而不使用barriers
    work work 1: 10
    2: 20
    work work 2: 40
    1: 20
    work 2: 60
    work 1: 30
    work 2: 80
    work 1: 40
    work 2: 100
    work 1: 50
    work 2: 120
    work 1: 60
    work 2: 140
    work 1: 70
    work 2: 160
    work 1: 80
    work 2: 180
    work 1: 90