Ist es klug, boost :: thread und boost :: mutex durch c ++ 11-Äquivalente zu ersetzen?

153

Motivation: Grund, warum ich darüber nachdenke, ist, dass mein genialer Projektmanager denkt, dass Boost eine weitere Abhängigkeit ist und dass es schrecklich ist, weil "Sie davon abhängen" (ich habe versucht, die Qualität von Boost zu erklären, und dann nach einiger Zeit aufgegeben :( ) Ein kleinerer Grund, warum ich das tun möchte, ist, dass ich C ++ 11-Funktionen lernen möchte, weil die Leute anfangen, Code darin zu schreiben. Also:

  1. Gibt es eine 1: 1-Zuordnung zwischen #include<thread> #include<mutex>und Boost-Äquivalenten?
  2. Würden Sie eine gute Idee in Betracht ziehen, Boost-Inhalte durch C ++ 11-
    Inhalte zu ersetzen? Meine Verwendung ist primitiv, aber gibt es Beispiele, bei denen std nicht bietet, was Boost bewirkt? Oder (Gotteslästerung) umgekehrt?

PS Ich benutze GCC, also sind Header da.

NoSenseEtAl
quelle
46
IMO Google Codierungsrichtlinien sind in vielerlei Hinsicht dumm ... Zum Beispiel. Sie erlauben
kein
5
Zitierrichtlinien: [Auto] beeinträchtigt die Lesbarkeit [weil es entfernt] überprüfte Redundanz (z. B. Typnamen), die für Leser hilfreich sein kann.
Andrew Tomazos
31
für (auto it = v.begin () ... :)
NoSenseEtAl
15
@ AndrewTomazos-Fathomling: Wirklich? Persönlich glaube ich nicht, dass ich mich jemals um den tatsächlichen Typ des Iterators gekümmert habe (naja, vielleicht ein paar Mal), sondern nur um die unterstützten Operationen ... Ich würde argumentieren, dass syntaktische Redundanz selten ein guter Gedanke ist (DRY).
Grizzly
16
Übrigens hat Google seine dummen Richtlinien geändert, so dass sie jetzt endlich Auto
NoSenseEtAl

Antworten:

192

Es gibt verschiedene Unterschiede zwischen Boost.Thread und der C ++ 11-Standard-Thread-Bibliothek:

  • Boost unterstützt das Löschen von Threads, C ++ 11-Threads nicht
  • C ++ 11 unterstützt std::async, Boost jedoch nicht
  • Boost verfügt über eine boost::shared_mutexSperre für mehrere Leser / einzelne Schreiber. Das Analoge std::shared_timed_mutexist nur seit C ++ 14 ( N3891 ) std::shared_mutexverfügbar , während es nur seit C ++ 17 ( N4508 ) verfügbar ist .
  • C ++ 11-Zeitüberschreitungen unterscheiden sich von Boost-Zeitüberschreitungen (obwohl sich dies bald ändern sollte, wurde Boost.Chrono akzeptiert).
  • Einige der Namen sind unterschiedlich (zB boost::unique_futurevs std::future)
  • Die Semantik der Argumentübergabe von std::threadunterscheidet sich von der Verwendung von boost::thread--- Boost boost::bind, für die kopierbare Argumente erforderlich sind. std::threadErmöglicht die Übergabe von Nur-Verschieben-Typen std::unique_ptrals Argumente. Aufgrund der Verwendung von boost::bindkann auch die Semantik von Platzhaltern wie _1in verschachtelten Bindungsausdrücken unterschiedlich sein.
  • Wenn Sie nicht explizit aufrufen join()oder detach()dann das boost::threadwird destructor und Zuweisungsoperator rufen detach()auf dem Thread - Objekt zerstört / zugewiesen. Bei einem C ++ 11- std::threadObjekt wird std::terminate()die Anwendung aufgerufen und abgebrochen.

Um den Punkt über Nur-Verschieben-Parameter zu verdeutlichen, gilt Folgendes in C ++ 11 und überträgt den Besitz des intvom temporären std::unique_ptrauf den Parameter, f1wenn der neue Thread gestartet wird. Wenn Sie jedoch verwenden, boost::threadfunktioniert es nicht, da es boost::bindintern verwendet wird, und std::unique_ptrkann nicht kopiert werden. Es gibt auch einen Fehler in der mit GCC bereitgestellten C ++ 11-Thread-Bibliothek, der verhindert, dass dies funktioniert, wie es auch std::bindin der dortigen Implementierung verwendet wird.

void f1(std::unique_ptr<int>);
std::thread t1(f1,std::unique_ptr<int>(new int(42)));

Wenn Sie Boost verwenden, können Sie wahrscheinlich relativ problemlos zu C ++ 11-Threads wechseln, wenn Ihr Compiler dies unterstützt (z. B. haben neuere Versionen von GCC unter Linux eine weitgehend vollständige Implementierung der im -std=c++0xModus verfügbaren C ++ 11-Thread-Bibliothek ).

Wenn Ihr Compiler keine C ++ 11-Threads unterstützt, können Sie möglicherweise eine Drittanbieterimplementierung wie Just :: Thread erhalten , dies ist jedoch immer noch eine Abhängigkeit.

Anthony Williams
quelle
1
Es gibt separate Sperr- / Entsperrmethoden für Leser und Schreiber ( lock/ unlockfür Schreiber vs. 'lock_shared / entsperren_shared' für Leser). Mehrere Leser können lock_shared aufrufen, ohne zu blockieren, solange keine Autoren es verwenden.
Dave S
2
Die shared_mutexDokumente finden Sie unter boost.org/doc/libs/1_47_0/doc/html/thread/… . Sie sperren den Mutex entweder als freigegeben oder als exklusiv und verwenden dann die entsprechende Entsperrfunktion. Sie können dazu auch die RAII-Typen verwenden (verwendet shared_lockeine gemeinsame Lesesperre lock_guardund unique_lockeine exklusive Sperre). Ich habe versucht, den Punkt über Nur-Verschieben-Typen zu klären.
Anthony Williams
3
Eine weitere Kleinigkeit, die mich gestolpert hat: In Boost löst der Destruktor eines laufenden Threads ihn ( boost.org/doc/libs/1_47_0/doc/html/thread/… ), während in C ++ der Destruktor eines laufenden Thread- Aufrufs beendet wird () (FDIS 30.3.1.3)
Cubbi
3
In C ++ 11 wird die try_scoped_lockFunktionalität von abgedeckt std::unique_lock. Es gibt einen Konstruktor, der einen Mutex und verwendet std::try_to_lockund dann try_lock()den Mutex anstelle von aufruft lock(). Siehe stdthread.co.uk/doc/headers/mutex/unique_lock/…
Anthony Williams
4
Ja, Boost.Thread ist dem C ++ 11-Standard viel näher gekommen, seit ich dies geschrieben habe, hauptsächlich aufgrund der Arbeit von Vicente Botet.
Anthony Williams
24

std::threadist weitgehend nachempfunden boost::thread, mit einigen Unterschieden :

  • Die nicht kopierbare Semantik von Boosts One-Handle-Maps-to-One-OS-Thread bleibt erhalten. Dieser Faden ist jedoch beweglich, um das Zurückführen des Fadens von den Werksfunktionen und das Einlegen in Behälter zu ermöglichen.
  • Dieser Vorschlag fügt dem hinzu boost::thread, was eine erhebliche Komplikation darstellt. Diese Änderung hat große Auswirkungen nicht nur auf den Thread, sondern auch auf den Rest der C ++ - Threading-Bibliothek. Es wird angenommen, dass diese große Änderung aufgrund des Nutzens gerechtfertigt ist.
    • Der Thread-Destruktor muss jetzt vor dem Trennen abbrechen aufrufen, um zu vermeiden, dass versehentlich untergeordnete Threads verloren gehen, wenn übergeordnete Threads abgebrochen werden.
    • Ein explizites Trennelement ist jetzt erforderlich, um das Trennen ohne Abbrechen zu aktivieren.
  • Die Konzepte des Thread-Handles und der Thread-Identität wurden in zwei Klassen unterteilt (sie sind dieselbe Klasse in boost::thread). Dies soll die Manipulation und Speicherung der Thread-Identität erleichtern.
  • Die Möglichkeit, eine Thread-ID zu erstellen, die garantiert mit keinem anderen verbindbaren Thread vergleichbar ist, wurde hinzugefügt (hat boost::threaddies nicht). Dies ist praktisch für Code, der wissen möchte, ob er von demselben Thread wie ein vorheriger Aufruf ausgeführt wird (rekursive Mutexe sind ein konkretes Beispiel).
  • Es gibt eine "Hintertür", über die das native Thread-Handle abgerufen werden kann, sodass Clients Threads bei Bedarf mithilfe des zugrunde liegenden Betriebssystems bearbeiten können.

Dies ist aus dem Jahr 2007, daher sind einige Punkte nicht mehr gültig: boost::threadhat native_handlejetzt eine Funktion und hat, wie Kommentatoren betonen, std::threadkeine Stornierung mehr.

Ich konnte keine signifikanten Unterschiede zwischen boost::mutexund feststellen std::mutex.

Alex B.
quelle
2
std::threadhat keine Stornierung; das ist boost::threades!
Anthony Williams
@Anthony bist du sicher, dass du nicht interrupt()für boost :: thread meinst ? Es scheint auch, dass es sich um einen ursprünglichen Vorschlag handelt, der sich seit 2007 geändert hat.
Alex B
4
Ja, die Aufhebung des Boosts wird als "Unterbrechung" bezeichnet. Ja, das ist ein alter Vorschlag. Der neueste öffentliche Entwurf des C ++ 11-Standards (der die Thread-Bibliothek enthält) ist open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3242.pdf
Anthony Williams
6

Es gibt einen Grund, nicht zu migrieren std::thread.

Wenn Sie statische Verknüpfungen verwenden, std::threadwerden diese aufgrund der folgenden Fehler / Funktionen unbrauchbar:

Wenn Sie anrufen std::thread::detachoder std::thread::joines zu einer Ausnahme oder einem Absturz führt, boost::threadfunktioniert dies in diesen Fällen in Ordnung.

ks1322
quelle
Ich sehe, dass ein Fehler NICHT BESTÄTIGT und der andere UNGÜLTIG ist. In einem Kommentar heißt es, der Reporter hätte dagegen verlinken sollen libpthread.a. Bist du dir absolut sicher, was du sagst?
einpoklum
1
@einpoklum, Sie sollten in der Lage sein, es mit zu verwenden Wl,--whole-archive -lpthread -Wl,--no-whole-archive, siehe diese Antwort zum Beispiel stackoverflow.com/a/23504509/72178 . Aber es ist kein sehr einfacher Weg, sich mit einer libpthread.aschlechten Idee zu verbinden und sie auch als schlecht zu betrachten.
ks1322
4
Können wir davon ausgehen, dass diese Fehler behoben sind, da dies jetzt 2016 ist? Die Fehler wurden 2012 veröffentlicht und ab gcc 4.9.2 wird C ++ 11 offiziell unterstützt, sodass wir C ++ 11 vor dem offiziellen Support nicht beschweren können.
Splash
6

Unternehmensfall

Wenn Sie Software für Unternehmen schreiben, die auf einer moderaten bis großen Vielfalt von Betriebssystemen ausgeführt werden muss und folglich mit einer Vielzahl von Compilern und Compilerversionen (insbesondere relativ alten) auf diesen Betriebssystemen erstellt werden muss, ist mein Vorschlag, sich davon fernzuhalten C ++ 11 insgesamt vorerst. Das bedeutet, dass Sie nicht verwenden können std::thread, und ich würde empfehlen, zu verwenden boost::thread.

Basic / Tech Startup Case

Wenn Sie für ein oder zwei Betriebssysteme schreiben, wissen Sie mit Sicherheit, dass Sie immer nur mit einem modernen Compiler erstellen müssen, der hauptsächlich C ++ 11 unterstützt (z. B. VS2015, GCC 5.3, Xcode 7), und Sie sind es noch nicht also abhängig von der Boost-Bibliothek std::thread könnte dann eine gute Option sein.

Meine Erfahrung

Ich persönlich mag gehärtete, stark genutzte, hochkompatible, hochkonsistente Bibliotheken wie Boost im Vergleich zu einer sehr modernen Alternative. Dies gilt insbesondere für komplizierte Programmierthemen wie Threading. Außerdem habe ich lange Zeit große Erfolge mit boost::thread(und Boost im Allgemeinen) in einer Vielzahl von Umgebungen, Compilern, Threading-Modellen usw. erzielt. Wenn es meine Wahl ist, entscheide ich mich für Boost.

Nicholas Smith
quelle
1
@UmNyobe Er hat aber recht. Viele Implementierungen von C ++ 11-Threading sind so kaputt, dass ich überrascht bin, dass die Leute überhaupt darüber nachdenken, es zu verwenden.
StaceyGirl
3

Mit Visual Studio 2013 std::mutexscheint sich das anders zu verhalten als das boost::mutex, was mir einige Probleme bereitete (siehe diese Frage ).

Robert Hegner
quelle
1

In Bezug auf std :: shared_mutex in C ++ 17 hinzugefügt

Die anderen Antworten hier geben einen sehr guten Überblick über die Unterschiede im Allgemeinen. Es gibt jedoch mehrere Probleme mit std::shared_mutexdieser Boost-Lösung.

  1. Aufrüstbare Mutices. Diese fehlen in std::thread. Sie ermöglichen es einem Leser, ein Upgrade auf einen Writer durchzuführen, ohne dass andere Writer vor Ihnen einsteigen können . Mit diesen können Sie beispielsweise eine große Berechnung vorverarbeiten (z. B. eine Datenstruktur neu indizieren), während Sie sich im Lesemodus befinden, und dann auf Schreiben aktualisieren, um die Neuindizierung anzuwenden, während Sie die Schreibsperre nur für kurze Zeit gedrückt halten.

  2. Gerechtigkeit. Wenn Sie eine konstante std::shared_mutexLeseaktivität mit a haben , werden Ihre Autoren auf unbestimmte Zeit gesperrt. Dies liegt daran, dass ein anderer Leser immer Vorrang hat, wenn er mitkommt. Mit erhalten boost:shared_mutexalle Threads schließlich Priorität. (1) Weder Leser noch Schriftsteller werden verhungern.

Das Wichtigste dabei ist, dass ein System mit sehr hohem Durchsatz ohne Ausfallzeiten und mit sehr hohen Konflikten std::shared_mutexniemals für Sie funktioniert, ohne manuell ein Prioritätssystem darauf aufzubauen. boost::shared_mutexfunktioniert sofort, obwohl Sie in bestimmten Fällen möglicherweise daran basteln müssen. Ich würde argumentieren, dass dieses std::shared_mutexVerhalten ein latenter Fehler ist, der darauf wartet, in den meisten Codes, die ihn verwenden, aufzutreten.

(1) Der tatsächlich verwendete Algorithmus basiert auf dem OS-Thread-Scheduler. Nach meiner Erfahrung gibt es bei gesättigten Lesevorgängen unter Windows längere Pausen (beim Erhalt einer Schreibsperre) als unter OSX / Linux.

Robert Fraser
quelle
0

Ich habe versucht, shared_ptr von std anstelle von boost zu verwenden, und ich habe tatsächlich einen Fehler in der gcc-Implementierung dieser Klasse gefunden. Meine Anwendung stürzte ab, weil der Destruktor zweimal aufgerufen wurde (diese Klasse sollte threadsicher sein und keine derartigen Probleme verursachen). Nach dem Wechsel zu boost :: shared_ptr sind alle Probleme verschwunden. Aktuelle Implementierungen von C ++ 11 sind noch nicht ausgereift.

Boost hat auch mehr Funktionen. Zum Beispiel bietet der Header in der Standardversion keinen Serializer für einen Stream (dh cout << Dauer). Boost hat viele Bibliotheken, die ihre eigenen usw. Äquivalente verwenden, aber nicht mit Standardversionen zusammenarbeiten.

Zusammenfassend lässt sich sagen, dass es sicherer ist, den Code so zu belassen, wie er ist, wenn Sie bereits eine Anwendung haben, die mit boost geschrieben wurde, anstatt sich um die Umstellung auf den C ++ 11-Standard zu bemühen.

user3323559
quelle
4
Der shared_ptrDestruktor muss nicht threadsicher sein. Es ist ein undefiniertes Verhalten, wenn ein Thread auf ein Objekt zugreift, während ein anderer Thread es zerstört. Wenn Sie der Meinung sind, dass Sie einen Fehler in GCCs shared_ptr gefunden haben, melden Sie ihn bitte , andernfalls verwenden Sie ihn mit der Wahrscheinlichkeit, dass Sie ihn falsch verwenden.
Jonathan Wakely