C ++ 11 Thread: Mehrere Threads warten auf eine Bedingungsvariable

8

Ich arbeite gerade an einem Problem, das ein erweitertes Producer-Worker-Modell simuliert. In diesem Problem gibt es 3 Arbeiter und 3 Werkzeuge, und damit die Arbeiter arbeiten können, brauchen sie 2 Werkzeuge (und Materialien, aber diese sind irrelevant). Wenn es & lt; 2 Werkzeuge in dem Tresor gibt, wird ein Arbeiter 2 nehmen. Andernfalls werden sie auf eine Bedingungsvariable warten, die signalisiert wird, wenn & gt; = 2 sind.

Das ist in Ordnung mit zwei Arbeitern: Einer wird arbeiten und dann die Werkzeuge zum Tresor zurückbringen, und der andere wartende Arbeiter wird aufwachen und zwei Werkzeuge nehmen. Das Problem ist, dass mit 3 Arbeitern immer einer hungern wird, um die Werkzeuge zu bekommen.

Nach einigen Tests habe ich bemerkt, dass Threads, die auf eine Zustandsvariable warten, in Stack-Form strukturiert sind. Ist es irgendwie möglich, es in die Warteschlange zu stellen? (1 wartet, 2 wartet und 3 wartet. Wenn 1 erwacht ist und einen anderen machen will, muss er hinter 2 und 3 warten.)

Hier ist eine Beispielausgabe. Der Code ist zu lang, also poste ich ihn, wenn es wirklich notwendig ist. Es gibt 3 Worker Threads und 1 Tool Mutex. Wer hungert, unterscheidet sich von jedem anderen Lauf.

%Vor%

(Wie Sie sehen können, bekommt 2 die Werkzeuge nie ...)

Aktualisierung: 2013/07/05 Ich habe etwas Code hinzugefügt.

%Vor%

Prozessor:

%Vor%

makeProducts:

%Vor%

getTools:

%Vor%

Danke an diejenigen, die geantwortet haben. Ich werde versuchen, heute Nacht eine Warteschlange mit mehreren Bedingungsvariablen zu implementieren.

(P.S. Gibt es eine bessere Möglichkeit, Code-Formatierung hier auf Stack Overflow zu machen? Anders als die vier Leerzeichen ...

    
user1745746 02.07.2013, 07:29
quelle

4 Antworten

9

std::condition_variable gibt nicht an, welcher wartende Thread beim Aufruf von notify_one aktiviert wird. Sie sollten daher Code schreiben, der nicht interessiert, welcher Thread geweckt wird. Das Standardmuster ist dasjenige, welches Thread geweckt wird, dieser Thread sollte die Arbeit erledigen, die erledigt werden muss.

Wenn Sie möchten, dass die Threads in einer bestimmten Reihenfolge aktiviert werden, verwenden Sie einen anderen Mechanismus. Sie könnten beispielsweise für jeden Thread ein eigenes std::condition_variable haben und dann die Threads in eine Warteschlange stellen, wenn sie Tools benötigen. Wenn ein Thread die Werkzeuge übergibt, könnte er dann die Zustandsvariable entsprechend dem Thread an der Vorderseite der Warteschlange signalisieren. Dieser Thread wird dann geweckt und die anderen werden schlafen (modulo-wecken).

    
Anthony Williams 02.07.2013, 10:17
quelle
3

Wenn mehrere Threads auf eine Bedingung warten, die Reihenfolge in dem sie geweckt werden ( notify_all ) oder was man ist erwacht ( notify_one ) ist nicht spezifiziert. Wenn Sie irgendeine Art brauchen Um zu bestellen, müssen Sie notify_all verwenden und implementieren dich selber. Sie können eine Warteschlange der Threads warten: vorher Warten Sie (aber nachdem Sie den Mutex erhalten haben), drücken Sie die Thread-ID auf das Ende der Warteschlange. In der Schleife, Schleife auf "dieser Thread bei Vor der Warteschlange und notwendigen Tools zur Verfügung. "Wenn Sie die Werkzeuge, entfernen Sie die ID von der Vorderseite der Warteschlange und rufen Sie an notify_all erneut.

    
James Kanze 02.07.2013 08:28
quelle
1

Das eigentliche Problem hier ist, dass wenn Sie Worker-Threads und eine begrenzte Menge an benötigten Ressourcen haben, es Ihnen egal sein sollte, welche Threads tatsächlich aktiviert sind, sollten Sie nur darauf achten, dass die Arbeit erledigt wird. Der einzige Unterschied ist hier in der Protokollierung. Die Anzahl der Threads, die Sie definiert haben, ist die Anzahl der Threads, die parallel ausgeführt werden können und die durch die Ressourcen auf eins beschränkt sind.

Wenn dies für Sie nicht in Ordnung ist, müssen Sie selbst Maßnahmen ergreifen, wie in anderen Antworten erläutert.

    
stefaanv 02.07.2013 10:01
quelle
0

Ein Ansatz könnte darin bestehen, einen vollwertigen Semaphor zu verwenden, der zwischen den Threads anstelle einer Bedingungsvariablen geteilt wird. Auf diese Weise können Sie auf eine bestimmte Anzahl warten.

%Vor%

Die Implementierung sieht so aus:

%Vor%     
ogni42 02.07.2013 09:41
quelle