当我试图用另一个线程唤醒一个线程时,我遇到了问题。简单的生产者/消费者。
代码下方。第85行是我不明白的原因,为什么它不起作用。生产者线程填充std :: queue并在消费者线程等待NOT std :: queue.empty()时调用std :: condition_variable.notify_one()。
提前感谢您提供任何帮助
#include <mutex>
#include <condition_variable>
#include <queue>
#include <string>
#include <iostream>
#include <thread>
// request
class request :
public std::mutex,
public std::condition_variable,
public std::queue<std::string>
{
public:
virtual ~request();
};
request::~request()
{
}
// producer
class producer
{
public:
producer(request &);
virtual ~producer();
void operator()();
private:
request & request_;
};
producer::producer(request & _request)
:
request_(_request)
{
}
producer::~producer()
{
}
void
producer::operator()()
{
while (true) {
std::lock_guard<std::mutex> lock(request_);
std::cout << "producer\n";
request_.push("something");
std::this_thread::sleep_for(std::chrono::seconds(1));
request_.notify_one();
}
}
class consumer
{
public:
consumer(request &);
virtual ~consumer();
void operator()();
private:
request & request_;
};
consumer::consumer(request & _request)
:
request_(_request)
{
}
consumer::~consumer()
{
}
void
consumer::operator()()
{
while (true) {
std::unique_lock<std::mutex> lock(request_); // <-- the problem
std::cout << "consumer\n";
request_.wait (
lock, [this] {return !request_.empty();}
);
request_.pop();
}
}
int
main()
{
// request
request request_;
// producer
std::thread producer_{producer(request_)};
// consumer
std::thread first_consumer_{consumer(request_)};
std::thread second_consumer_{consumer(request_)};
// join
producer_.join();
first_consumer_.join();
second_consumer_.join();
}
答案 0 :(得分:11)
下面修正了以下修改代码:
cout
(我使用endl
执行此操作)以便立即打印输出,这样可以更轻松地查看正在发生的事情。"consumer"
,因为这是消费者消费的时候,否则你会得到误导性的输出,表明消费者正在睡觉时,而不是当它开始工作时。您的代码的主要问题是生产者从未给过消费者一个运行的机会。它添加到队列中,睡眠一秒钟(仍然持有互斥锁)然后通知条件变量(仍然持有互斥锁),然后真的很快释放互斥锁并再次获取它。可能你看到的是消费者线程得到通知,试图获取互斥锁,发现它仍然被锁定(由生产者线程),所以又回到了睡眠状态。生产者从来没有释放过互斥锁,足以让另一个线程获得它。您可能通过在生产者循环开始时添加std::this_thread::yield()
,锁定互斥锁之前的,但可能能够获得更好的结果,但依赖于{的算法{1}}正确性通常被打破(事实上,我的测试没有任何区别);最好修复生产者循环,让消费者有机会醒来并跑步。
这是工作代码:
yield()
答案 1 :(得分:0)
您必须在调用std::unique_lock
之前解锁notify_one()
,否则您的while循环将尝试在同一个线程中锁定两次。这对生产者和消费者都有效。
但是,我同意那些说你的请求推导非常误导的人。你应该使用作文。 如果你给我10分钟,我可能会想出一些有用的东西:)