Atomare Operationen auf 'unique_ptr'

8

std::shared_ptr hat Spezialisierungen für atomare Operationen wie atomic_compare_exchange_weak und family, aber ich Dokumentation zu entsprechenden Spezialisierungen für std::unique_ptr kann nicht gefunden werden. Sind da irgendwelche? Wenn nicht, warum nicht?

    
J. Doe 28.01.2016, 17:09
quelle

3 Antworten

7

Nein, es gibt keine atomaren Standardfunktionen für std::unique_ptr .

Ich fand ein Argument dafür, warum nicht in Atomic Smart Pointers ( N4058) von Herb Sutter

  

Lawrence Crowl antwortete auf hinzufügen:

     

Einer der Gründe, warum shared_ptr locking so ist, ist, eine Situation zu vermeiden, in der wir die Vorbedingung für den atomaren Template-Parameter schwächen, dass sie trivial ist und daher kein Deadlock riskiert.

     

Das heißt, wir könnten die Anforderung schwächen, so dass der Argumenttyp nur lockfrei oder vielleicht nur nicht rekursiv sein muss.

     

Obwohl trivial für vernünftig testbare Eigenschaften sorgt, sehe ich keinen effektiven Mechanismus, um auf die schwächere Eigenschaft zu testen.

Dieser Vorschlag wurde der Concurrency-Untergruppe zugewiesen und ist noch nicht verfügbar. Sie können den Status unter JTC1 / SC22 / WG21 - Papers 2014 Mailing2014 überprüfen -07

    
NathanOliver 28.01.2016, 17:34
quelle
4

Seien Sie vorsichtig, wenn Sie einen veränderbaren unique_ptr -Wert zwischen Threads teilen, ist dies selten sinnvoll, selbst wenn der Zeiger selbst atomar ist. Wenn sich sein Inhalt ändert, wie können andere Threads davon erfahren? Sie können nicht.

Betrachten Sie dieses Beispiel:

%Vor%

Wie kann Thread A verhindern, dass nach dem Aufruf von p.get() ?

Wenn Sie ein Objekt zwischen Threads teilen möchten, verwenden Sie shared_ptr , das genau für diesen Zweck eine Referenzzählung hat.

Wenn Sie wirklich gewollt haben, können Sie immer Ihre eigene atomic_unique_ptr , etwas in den folgenden Zeilen (vereinfacht) rollen:

%Vor%

Hinweis: Der Code in diesem Beitrag wird hiermit in Public Domain veröffentlicht.

    
rustyx 15.03.2017 13:25
quelle
3

Der Grund, warum es möglich ist, eine atomare Instanz von std::shared_ptr bereitzustellen, und dies ist nicht möglich für std::unique_ptr , ist in ihrer Signatur angedeutet. Vergleichen Sie:

  • std::shared_ptr<T> vs
  • std::unique_ptr<T, D> wobei D der Typ des Deleters ist.

std::shared_ptr muss einen Kontrollblock zuweisen, in dem die starke und schwache Zählung beibehalten wird, so dass die Typ-Löschung des Löschers mit einem trivialen Aufwand verbunden ist (ein einfach etwas größerer Steuerblock).

Daher ähnelt das Layout von std::shared_ptr<T> im Allgemeinen:

%Vor%

Und es ist möglich, den Austausch dieser beiden Zeiger atomar durchzuführen.

std::unique_ptr hat eine Null-Overhead-Richtlinie; Die Verwendung von std::unique_ptr sollte keinen Overhead verursachen, verglichen mit der Verwendung eines rohen Zeigers.

Daher ähnelt das Layout von std::unique_ptr<T, D> im Allgemeinen:

%Vor%

Wo die tuple EBO (Empty Base Optimization) verwendet, so dass immer, wenn D null ist, sizeof(unique_ptr<T>) == sizeof(T*) .

In den Fällen, in denen D jedoch NICHT null ist, läuft die Implementierung auf:

hinaus %Vor%

Dieser D ist der Kicker hier; Es ist im Allgemeinen nicht möglich zu garantieren, dass D auf atomare Weise ausgetauscht werden kann, ohne auf Mutexe angewiesen zu sein.

Daher ist es nicht möglich, eine std::atomic_compare_exchange* -Suite von spezialisierten Routinen für das generische std::unique_ptr<T, D> bereitzustellen.

Beachten Sie, dass der Standard nicht garantiert, dass sizeof(unique_ptr<T>) == sizeof(T*) AFAIK, obwohl es eine allgemeine Optimierung ist.

    
Matthieu M. 10.01.2018 13:49
quelle