在单个生产者和多个消费者案例的情况下,线程连接挂起。 我附上以下代码库:
1)这是消费者线程
class ConsumerThread-
{
wqueue<WorkItem*>& m_queue;
-
public:
ConsumerThread(wqueue<WorkItem*>& queue) : m_queue(queue) {}
std::thread start() {
return std::thread( [=] {runThr();} );
}
-
void runThr() {
// Remove 1 item at a time and process it. Blocks if no items are-
// available to process.
for (int i = 0;; i++) {
printf("thread %lu, loop %d - waiting for item...\n",-
std::this_thread::get_id(), i);
WorkItem* item = (WorkItem*)m_queue.remove();
printf("thread %lu, loop %d - got one item\n",-
std::this_thread::get_id(), i);
printf("thread %lu, loop %d - item: message - %s, number - %d\n",-
std::this_thread::get_id(), i, item->getMessage(),-
item->getNumber());
delete item;
}
}
};
2)这是工作项
class WorkItem
{
std::string m_message;
int m_number;
-
public:
WorkItem(const char* message, int number)-
: m_message(message), m_number(number) {}
~WorkItem() {}
-
const char* getMessage() { return m_message.c_str(); }
int getNumber() { return m_number; }
};
3)。该类具有生产者推送的队列,消费者使用WorkItem。
template <typename T> class wqueue
{
std::list<T> m_queue;
std::mutex m_mutex;
std::condition_variable m_condv;-
public:
wqueue() {}
~wqueue() {}
void add(T item) {
m_mutex.lock();
m_queue.push_back(item);
m_condv.notify_one();
m_mutex.unlock();
}
T remove() {
std::unique_lock<std::mutex> lk(m_mutex);
while(m_queue.size() == 0)
m_condv.wait(lk);
T item = m_queue.front();
m_queue.pop_front();
return item;
}
int size() {
m_mutex.lock();
int size = m_queue.size();
m_mutex.unlock();
return size;
}
};
4)这是包含主函数
的类int main(int argc, char* argv[])
{
// Process command line arguments
if ( argc != 2 ) {
printf("usage: %s <iterations>\n", argv[0]);
exit(-1);
}
int iterations = atoi(argv[1]);
// Create the queue and consumer (worker) threads
wqueue<WorkItem*> queue;
ConsumerThread* thread1 = new ConsumerThread(queue);
ConsumerThread* thread2 = new ConsumerThread(queue);
std::thread t1 = thread1->start();
std::thread t2 = thread2->start();
t1.join();
t2.join();
// Add items to the queue
WorkItem* item;
for (int i = 0; i < iterations; i++) {
item = new WorkItem("abc", 123);
queue.add(item);
item = new WorkItem("def", 456);
queue.add(item);
item = new WorkItem("ghi", 789);
queue.add(item);
}
第4节中提到的t1.join()和t2.join()挂起。
答案 0 :(得分:1)
您的消费者线程没有终止条件,因此它永远运行:
for (int i = 0;; i++) // never ends
加入一个线程不会神奇地让它突破它的循环,你需要设置结束标志或其他东西。
当wqueue
为空时,尝试remove()
元素的所有线程都会阻塞:
while(m_queue.size() == 0)
m_condv.wait(lk);
在中添加任何内容之前,您尝试join()
线程。
答案 1 :(得分:1)
行为没有任何问题,在线程对象上调用join()
只会等到线程完成后再继续。你的问题是你的线程没有终止,这是一个完全不同的问题。
特别是在生产者 - 消费者设置中,两个同伴通常都坐着等待工作。除非你明确告诉他们不要再等待工作,否则他们会永远坐在那里!如果你反过来等待他们完成,你也会永远等待,这是你的问题。你需要发出信号来停止循环,另外你可能不得不打断它们等待工作。