Ist dies der richtige Ansatz für eine Thread-sichere Queue-Klasse?

7

Ich frage mich, ob dies der richtige Ansatz zum Schreiben einer thread-sicheren Warteschlange in C ++ ist?

%Vor%

Sie haben die Idee ... Ich frage mich nur, ob das der beste Ansatz ist. Danke!

BEARBEITEN: Wegen der Fragen, die ich bekomme, wollte ich klarstellen, dass der Mutex ein boost :: mutex

ist     
Polaris878 18.10.2009, 02:31
quelle

6 Antworten

8

Herb Sutter schrieb letztes Jahr einen ausgezeichneten Artikel ausgezeichneten Artikel im Dr. Dobbs Journal die Hauptanliegen für eine thread-sichere, lock-freie Single-Producer-Single-Consumer-Queue-Implementierung. (Die Korrekturen über eine Implementierung der letzten Monat veröffentlicht.)

Sein Follow-up-Artikel in der nächsten Ausgabe behandelte einen allgemeineren Ansatz für eine Warteschlange für mehrere Benutzer gleichzeitig vollständige Diskussion über mögliche Fallstricke und Leistungsprobleme.

Es gibt noch ein paar Artikel zu ähnlichen Nebenläufigkeitsthemen.

Viel Spaß.

    
greyfade 18.10.2009, 04:14
quelle
19

Ich empfehle, die Boost-Threading-Bibliotheken zu verwenden, um Sie dabei zu unterstützen.

Ihr Code ist in Ordnung, außer dass wenn Sie Code in C ++ wie

schreiben %Vor%

Wenn der Code im Abschnitt // do something eine Ausnahme auslöst, wird die Sperre niemals aufgehoben. Die Boost-Bibliothek löst dies mit ihren Klassen wie lock_guard , in dem Sie ein Objekt initialisieren, das im Konstruktor eine Sperre erhält und dessen Destruktor die Sperre aufhebt. Auf diese Weise wissen Sie, dass Ihr Schloss immer freigegeben wird. Andere Sprachen erreichen dies durch try / finally-Anweisungen, aber C ++ unterstützt dieses Konstrukt nicht.

Was passiert insbesondere, wenn Sie versuchen, aus einer Warteschlange ohne Elemente zu lesen? Ist das eine Ausnahme? Wenn ja, dann würde Ihr Code auf Probleme stoßen.

Wenn Sie versuchen, das erste Element zu bekommen, möchten Sie wahrscheinlich prüfen, ob etwas da ist, und dann schlafen gehen, wenn nicht und warten, bis etwas ist. Dies ist ein Job für ein Bedingung -Objekt , auch von der Boost-Bibliothek bereitgestellt, wenn auch auf einer niedrigeren Ebene verfügbar.

    
Eli Courtwright 18.10.2009 02:40
quelle
6

Von einem Threading-Point aus gesehen, der für eine einfache Thread-sichere Warteschlange richtig aussieht.

Sie haben jedoch ein Problem: Das pop () -Parameter von std :: queue gibt das aus der Warteschlange herausgefallene Element nicht zurück. Was Sie tun müssen, ist:

%Vor%

Sie möchten in diesem Fall keine Referenz zurückgeben, da das referenzierte Element aus der Warteschlange entfernt und zerstört wird.

Sie müssen auch eine öffentliche size () -Funktion haben, um Ihnen zu sagen, wie viele Elemente sich in der Warteschlange befinden (oder dass Sie den Fall bearbeiten müssen, in dem Pop () aufgerufen wird und in dem sich keine Elemente befinden die Warteschlange).

Bearbeiten: Obwohl Eli Courtwright darauf hinweist, müssen Sie vorsichtig sein, wenn die Warteschlangenoperationen Ausnahmen auslösen, und die Verwendung von Boost ist eine gute Idee.

    
James McNellis 18.10.2009 02:35
quelle
1

Hängt davon ab, was Ihre Ziele sind. Auf diese Weise erstellt, blockiert Ihr "Leser" -Client Ihren "Schreiber" -Client. Sie sollten in Betracht ziehen, eine "Bedingung" zu verwenden, um Deadlocks usw. zu vermeiden.

    
jldupont 18.10.2009 02:38
quelle
1

Der Ansatz, den Sie zu implementieren versuchen, ist ein Locking-Ansatz. Es funktioniert, außer, dass wenn Sie ein einfaches "Mutex" -Objekt verwenden, dessen Leistung sich als enttäuschend erweist (sein Lock-Unlock-Overhead ist ziemlich hoch). Es ist schwer zu sagen, ob es gut ist oder nicht, da wir nicht wissen, was Ihre Leistungsanforderungen und Erwartungen sind.

Da die Operationen, die Sie in "gesperrten" Segmenten Ihres Codes ausführen, ziemlich schnell sind, kann es sinnvoll sein, anstelle eines echten Mutex oder einer Kombination aus beiden eine Drehsperre zu verwenden. Dadurch erhalten Sie eine viel bessere Leistung. Vielleicht implementiert dein "Mutex" das alles schon (keine Möglichkeit zu wissen, da du keine Details darüber angegeben hast, was sich hinter diesem Namen versteckt).

Und schließlich, wenn Sie zufällig nach der besten Leistung suchen, möchten Sie vielleicht den lockfreien Synchronisierungsansatz lesen, der eine völlig andere Geschichte ist. Lock-Free-Methoden sind jedoch in der Regel viel schwieriger zu implementieren.

    
AnT 18.10.2009 03:12
quelle
1

Wie Jean-Lou Dupont darauf hingewiesen hat, ist Ihr aktueller Code ziemlich anfällig für Deadlocks. Als ich das getan habe, habe ich drei Sperren verwendet: zwei gezählte Semaphore und einen Mutex. Die gezählten Semaphoren signalisieren wenn:

  1. Es gibt Platz zum Einfügen eines Objekts
  2. Dort muss mindestens ein Objekt aus der Warteschlange abgerufen werden
Der Mutex wird nur verwendet, während ein Element tatsächlich in die Warteschlange gestellt wird oder ein Element aus der Warteschlange abgerufen wird. Es wird jedoch niemals versucht, den Mutex zu sperren, bis wir wissen, dass das Einfügen oder Abrufen sofort erfolgreich sein kann.     
Jerry Coffin 18.10.2009 17:33
quelle