为什么修改后的引用不改出线程?
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
,代码应该可以工作。
但是你根本不需要这里的flag
。 dq.empty()
是解锁 popper 所需的唯一条件(而 pusher 根本不需要等待)。
我目前正在练习多线程和内存管理,我正在尝试实现以下内容:多个线程将请求推送到一个双端队列中,另一个线程将它们弹出并打印。
函数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
,代码应该可以工作。
但是你根本不需要这里的flag
。 dq.empty()
是解锁 popper 所需的唯一条件(而 pusher 根本不需要等待)。