============================== Antworten und Lösungsvorschlag ============================== Antworten zu den einzelnen Fragen: * Die _capture_ im Konstruktor erfasst `this`. Das ist der Zeiger auf das eigene Objekt. Dieser Zeiger ist notwendig, um den Aufruf von `process_jobs` zu ermöglichen. Da es sich dabei um einen Zeiger handelt, ist eine _capture_ mit einer Zuweisung hierfür ausreichend. Eine Referenz wäre auch zulässig. * Der Thread darf erst starten, wenn auch `mutex` und `cv` initialisiert sind. Die Reihenfolge der Initialisierung hängt davon ab, in welcher Reihenfolge die einzelnen Komponenten deklariert sind. In der Vorlage war der Thread `t` zuerst deklariert und würde somit vor dem `mutex` und dem `cv`-Objekt initialisiert werden. Natürlich ließe sich die Reihenfolge der Deklarationen anpassen. Im Sinne einer defensiven Programmierung erscheint es hier aber geschickter, den Start des Threads auf einen Zeitpunkt zu verschieben, zu dem garantiert alle Komponenten initialisiert sind -- unabhängig von der Reihenfolge der Deklarationen. Für viele wäre es doch sehr überraschend, wenn ein potentieller Crash eines Programms nur von der Reihenfolge der Deklarationen abhängen würde. Und Warnungen würde es hier nicht geben. * Das Programm terminierte mit einem Aufruf von `std::terminate`, weil das Objekt `worker` dekonstruiert wurde, obwohl dessen Thread `worker.t` noch lief. Dies ist nicht zulässig. Somit muss der Destruktor - sich mit der Beendigung des Threads mit `t.join()` synchronisieren und - dann natürlich auch dafür sorgen, dass der Thread bei passender Gelegenheit terminiert. Die passende Gelegenheit erscheint hier das Abarbeiten der restlichen Jobs. 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: :import:session16/worker2.cpp :navigate: up -> doc:index back -> doc:session16/page01 next -> doc:session16/page03