Antworten und Lösungsvorschlag

Antworten zu den einzelnen Fragen:

Die folgende Lösung sieht die zusätzliche Variable finished vor, die auf true gesetzt wird, sobald der Destruktor beginnt. Danach erfolgt eine Notifikation (der Thread könnte ja gerade wegen einer leeren Job-Queue warten) und schließlich der Aufruf von t.join. Die Methode process_jobs wurde erweitert, so dass auf das Setzen von finished reagiert wird, d.h. die Schleife wird verlassen, sobald alle verbleibenden Jobs abgearbeitet sind und finished gesetzt ist:

#include <cassert>
#include <condition_variable>
#include <cstdio>
#include <functional>
#include <list>
#include <mutex>
#include <thread>
#include <utility>

struct Worker {
   public:
      using Job = std::function<void()>;
      Worker() : finished(false) {
         t = std::thread([=]() { process_jobs(); });
      }
      ~Worker() {
         {
            std::unique_lock<std::mutex> lock(mutex);
            finished = true;
         }
         cv.notify_one();
         t.join();
      }
      void submit(Job job) {
         std::unique_lock<std::mutex> lock(mutex);
         jobs.push_back(std::move(job));
         cv.notify_one();
      }
   private:
      bool finished;
      std::thread t;
      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);
               if (jobs.empty() && !finished) {
                  cv.wait(lock);
               }
               if (jobs.empty() && finished) break;
               job = std::move(jobs.front());
               jobs.pop_front();
            }
            /* execute job */
            job();
         }
      }
};

int main() {
   Worker worker;
   worker.submit([]() { std::printf("Hi, this is your first job!\n"); });
   worker.submit([]() { std::printf("Now you get another job.\n"); });
}