一个生产者线程,几个消费者

时间:2015-09-16 10:46:42

标签: c++ multithreading c++11

我有一个生产者线程和几个消费者,每个消费者都拥有:拥有数据和唯一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是对队列的引用。 但是我怎样才能以更好的方式同步它呢? 提前致谢。 附:队列总是有数据,最后的数据必须说“退出”。

4 个答案:

答案 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)

如果您不是为了研究/学习而是为了生产代码,我建议使用众多实现之一。正确,有效和可扩展地实现这一点并不容易,但其他人已经解决了这些问题。有很多选择,例如