线程连接挂起

时间:2015-10-18 12:44:53

标签: c++ multithreading

在单个生产者和多个消费者案例的情况下,线程连接挂起。 我附上以下代码库:

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()挂起。

2 个答案:

答案 0 :(得分:1)

您的消费者线程没有终止条件,因此它永远运行:

for (int i = 0;; i++) // never ends

加入一个线程不会神奇地让它突破它的循环,你需要设置结束标志或其他东西。

wqueue为空时,尝试remove()元素的所有线程都会阻塞:

    while(m_queue.size() == 0)
        m_condv.wait(lk);

在中添加任何内容之前,您尝试join()线程

答案 1 :(得分:1)

行为没有任何问题,在线程对象上调用join()只会等到线程完成后再继续。你的问题是你的线程没有终止,这是一个完全不同的问题。

特别是在生产者 - 消费者设置中,两个同伴通常都坐着等待工作。除非你明确告诉他们不要再等待工作,否则他们会永远坐在那里!如果你反过来等待他们完成,你也会永远等待,这是你的问题。你需要发出信号来停止循环,另外你可能不得不打断它们等待工作。