Lösungsvorschlag

Das Problem ist, dass nach dem Aufruf des äußeren submit sofort am Ende von main der Dekonstruktor des Thread-Pools aufgerufen wird und somit finished auf true gesetzt wird. Während sich einer der beiden Threads mit dem ersten Job beschäftigt, findet der andere Thread finished auf true gesetzt vor zusammen mit einer leeren Liste von Jobs. Das nimmt dieser zum Anlass, seine Tätigkeit zu terminieren. Das hat dann die Konsequenz, das all die neu erzeugten Jobs nur von dem einen verbliebenen Thread ausgeführt werden können.

Solange noch Threads aktiv mit der Abarbeitung von Jobs beschäftigt sind, sollten die anderen nicht vorzeitig terminieren, da immer noch neue Jobs hinzukommen können.

#include <cassert>
#include <condition_variable>
#include <functional>
#include <iostream>
#include <list>
#include <mutex>
#include <thread>
#include <utility>
#include <vector>

struct ThreadPool {
   public:
      using Job = std::function<void()>;
      ThreadPool(unsigned int nof_threads) :
            nof_threads(nof_threads), active(0),
            finished(false), threads(nof_threads) {
         for (auto& t: threads) {
            t = std::thread([=]() { process_jobs(); });
         }
      }
      ~ThreadPool() {
         {
            std::unique_lock<std::mutex> lock(mutex);
            finished = true;
         }
         cv.notify_all();
         for (auto& t: threads) {
            t.join();
         }
      }
      void submit(Job job) {
         std::unique_lock<std::mutex> lock(mutex);
         jobs.push_back(std::move(job));
         cv.notify_one();
      }
   private:
      unsigned int nof_threads;
      unsigned int active;
      bool finished;
      std::vector<std::thread> threads;
      std::mutex mutex;
      std::condition_variable cv;
      std::list<Job> jobs;

      void process_jobs() {
         for(;;) {
            Job job;
            /* fetch job */
            {
               std::unique_lock<std::mutex> lock(mutex);
               while (jobs.empty() && (active > 0 || !finished)) {
                  cv.wait(lock);
               }
               if (jobs.empty() && active == 0 && finished) break;
               job = std::move(jobs.front());
               jobs.pop_front();
               ++active;
            }
            /* execute job */
            job();
            {
               std::unique_lock<std::mutex> lock(mutex);
               --active;
            }
         }
         /* if one thread finishes, all others have to finish as well */
         cv.notify_all();
      }
};

int main() {
   ThreadPool pool(2);
   pool.submit([&]() {
      pool.submit([&]() {
         pool.submit([]() {
            std::cout << "Hello guys, I'm " << std::this_thread::get_id() <<
               std::endl;;
         });
         std::cout << "Hi guys, I'm " << std::this_thread::get_id() <<
            std::endl;;
      });
      pool.submit([&]() {
         pool.submit([]() {
            std::cerr << "O wonder, I'm " << std::this_thread::get_id() <<
               std::endl;;
         });
         std::cerr << "Huhu guys, I'm " << std::this_thread::get_id() <<
            std::endl;;
      });
      std::cout << "Hi, this is thread " << std::this_thread::get_id() <<
         std::endl;;
   });
}
$shell> g++ -O3 -g -I/home/numerik/pub/hpc/session16 -std=c++11 -o tpool3 tpool3.cpp
$shell> ./tpool3
Hi, this is thread 2
Hi guys, I'm 3
Huhu guys, I'm Hello guys, I'm 3
O wonder, I'm 2