我有一个生产者线程和几个消费者,每个消费者都拥有:拥有数据和唯一ID的队列。 我使用std :: map来识别线程的每个队列。
typedef std::map<int, std::queue<Task>> TaskMap;
TaskMap inputQueue;
TaskMap outputQueue;
每个使用者线程使用其队列中的数据,如果队列为空,则线程必须等待数据。 如果我想只使用一个线程,我可以使用std :: condition_variable与std :: unique_lock,但我有几个消费者,所以我需要几个std :: condition_variable,但我不能将它们保存在容器中(复制/赋值是删除)。 所以我使用这样的代码
while(q.empty()) {
std::cout << "waiting...\n";
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
其中q是对队列的引用。 但是我怎样才能以更好的方式同步它呢? 提前致谢。 附:队列总是有数据,最后的数据必须说“退出”。
答案 0 :(得分:2)
因为每个消费者都有自己的队列,并且所有消费者只有一个生产者,所以它实际上是一个生产者一个消费者的场景。
换句话说,您没有在所有消费者之间共享一个队列。
答案 1 :(得分:1)
一个std::conditional_variable
只有一个std::mutex
就足够了。
Task t;
{
std::unique_lock<std::mutex> lock(mtx);
while (q.empty())
cond_var.wait(lock);
t = std::move(q.front());
q.pop_front();
}
主线程将执行
{
std::lock_guard<std::mutex> lock(mtx);
q.emplace_front(/*...*/);
cond_var.notify_all();
}
主线程将唤醒所有线程,但大多数线程将重新进入休眠状态,因为它们的队列仍然是空的。
答案 2 :(得分:0)
调用此任务的OOP:
class ConcurentTaskQueue{
std::mutex lock;
std::condition_variable m_ConditionVariable;
std::queue<Task> m_TaskQueue;
public:
Task getTask(){
std::unique_lock<std::mutex> synchLock (lock); //NOTE: consider doing this with a while(programIsRunning){} loop
while(m_TaskQueue.empty()){
m_ConditionVariable.wait(synchLock);
}
Task task(std::move(m_TaskQueue.front()));
m_TaskQueue.pop();
return task;
}
void addTask (Task task){
std::unique_lock<std::mutex> synchLock (lock);
m_TaskQueue.push(std::move(task));
m_ConditionVariable.notify_one();
}
};
现在简单地说:
std::map<size_t,ConcurentTaskQueue> inputQueue;
std::thread producer ([&]{
Task task = produceTask()
inputQueue[ID].addTask(task);
});
std::thread consumer1([&]{
Task task = inputQueue[ID].getTask();
});
std::thread consumer2([&]{
Task task = inputQueue[ID].getTask();
});
EDIT2: 使用线程池
答案 3 :(得分:0)
如果您不是为了研究/学习而是为了生产代码,我建议使用众多实现之一。正确,有效和可扩展地实现这一点并不容易,但其他人已经解决了这些问题。有很多选择,例如