为什么修改后的引用不改出线程?

Why modified reference does not change out of thread?

我目前正在练习多线程和内存管理,我正在尝试实现以下内容:多个线程将请求推送到一个双端队列中,另一个线程将它们弹出并打印。

函数pusher获取对以下内容的引用:互斥体、条件变量、消息双端队列、指示双端队列是否被另一个线程写入的标志以及要重复推送的消息。

函数 popper 除了消息之外得到相同的参数。

我的代码如下:

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

void pusher(std::deque<int>& dq, std::mutex& mu, std::condition_variable& cond, bool& flag, int value)//function to insert value into deque
{
    while (true)
    {
        std::unique_lock<std::mutex> locker(mu);
        cond.wait(locker, [dq, flag]() {return flag == false; });
        flag = true;
        dq.push_back(value);
        std::cout << "pushing: " << value << std::endl;
        flag = false;
        locker.unlock();
        cond.notify_all();
        std::this_thread::sleep_for(std::chrono::seconds(1));
    }
}

void popper(std::deque<int>& dq, std::mutex& mu, std::condition_variable& cond, bool& flag)
{
    while (true)
    {
        std::unique_lock<std::mutex> locker(mu);
        cond.wait(locker, [dq, flag]() {return (!dq.empty() && flag == false); });
        flag = true;
        std::cout << "popping: " << dq.front() << std::endl;
        dq.pop_front();
        flag = false;
        locker.unlock();
        cond.notify_all();
    }
}


int main()
{
    std::deque<int>dq;
    std::mutex mu;
    std::condition_variable cond;
    bool flag = false;
    std::thread th1(pusher, std::ref(dq), std::ref(mu), std::ref(cond), std::ref(flag), 1);
    std::thread th2(popper, std::ref(dq), std::ref(mu), std::ref(cond), std::ref(flag));
    th1.join();
    th2.join();
    return 0;
}

当 运行 将这段代码 运行 变成一个问题时: popper 线程没有唤醒,而 pusher 线程无限期地继续。 但是,这次尝试使用指针而不是线程进行相同操作时,一切都按预期工作:

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


void pusher(std::mutex* mu, std::condition_variable* cond, std::deque<int>* dq, int* flag, int value)//function to insert value into deque
{
    while (true)
    {
        std::unique_lock<std::mutex> locker(*mu);
        cond->wait(locker, [dq, flag]() {return *flag == false; });
        *flag = true;
        dq->push_back(value);
        std::cout << "pushing: " << value << std::endl;
        *flag = false;
        locker.unlock();
        cond->notify_all();
        std::this_thread::sleep_for(std::chrono::seconds(1));
    }
}

void popper(std::mutex* mu, std::condition_variable* cond, std::deque<int>* dq, int* flag)//function to extract values from deque
{
    while (true)
    {
        std::unique_lock<std::mutex> locker(*mu);
        cond->wait(locker, [dq, flag]() {return (!dq->empty() && *flag == false); });
        *flag = true;
        std::cout << "popping: " << dq->front() << std::endl;
        dq->pop_front();
        *flag = false;
        locker.unlock();
        cond->notify_all();
    }
}

int main()
{
    int flag = false;
    std::mutex mu;
    std::condition_variable cond;
    std::deque<int> dq;
    std::thread th1(pusher, &mu, &cond, &dq, &flag, 1);

    std::thread th2(popper, &mu, &cond, &dq, &flag);
    th1.join();
    th2.join();

    return 0;
}

我怀疑在推送线程之外没有修改双端队列,因此不满足条件变量的条件。 可能是什么原因造成的?

问题在这里:

    cond->wait(locker, [dq, flag]() {return (!dq->empty() && *flag == false); });

尽管 dq, flag 是引用,但上面的内容是按值捕获的。这与您在启动线程时使用 std::ref() 的问题相同。

将其更改为 &dg, &flag,代码应该可以工作。

但是你根本不需要这里的flagdq.empty() 是解锁 popper 所需的唯一条件(而 pusher 根本不需要等待)。