title: Thread join hangs
body: <p>Thread join is hanging in case of single producer and multiple consumer case.
  I am attaching the codebase below:</p>
  
  <p>1) This is the Consumer Thread</p>
  
  <pre><code>class ConsumerThread-
  {
      wqueue&lt;WorkItem*&gt;&amp; m_queue;
  -
    public:
      ConsumerThread(wqueue&lt;WorkItem*&gt;&amp; 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-&gt;getMessage(),-
                     item-&gt;getNumber());
              delete item;
          }
      }
  };
  </code></pre>
  
  <p>2) This is Work Item</p>
  
  <pre><code>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; }
  };
  </code></pre>
  
  <p>3).  This class is has the queue where the producer pushes and consumers consume the WorkItem.</p>
  
  <pre><code>template &lt;typename T&gt; class wqueue
  {
      std::list&lt;T&gt;                  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&lt;std::mutex&gt; 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;
      }
  };
  </code></pre>
  
  <p>4) This is the class containing the main function</p>
  
  <pre><code>int main(int argc, char* argv[])
  {
  
      // Process command line arguments
      if ( argc != 2 ) {
          printf("usage: %s &lt;iterations&gt;\n", argv[0]);
          exit(-1);
      }
      int iterations = atoi(argv[1]);
  
      // Create the queue and consumer (worker) threads
      wqueue&lt;WorkItem*&gt;  queue;
      ConsumerThread* thread1 = new ConsumerThread(queue);
      ConsumerThread* thread2 = new ConsumerThread(queue);
  
      std::thread t1 = thread1-&gt;start();
      std::thread t2 = thread2-&gt;start();
  
      t1.join();
      t2.join();
  
      // Add items to the queue
      WorkItem* item;
      for (int i = 0; i &lt; 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);
      }
  </code></pre>
  
  <p>The  t1.join() and t2.join() hangs mentioned in the section 4.</p>