2013-06-01 11 views
34

I durch Anthony Williams lese "C++ Concurrency in Action" und in Kapitel 5, die über das neue Multithreading-fähiges Speichermodell und atomare Operationen sprechen, und er sagt: fürFunktioniert std :: atomic <std::string> richtig?

Um std::atomic<UDT> zu verwenden einige benutzerdefinierte UDT, muss dieser Typ einen trivialen Kopie Zuweisungsoperator haben.

Wie ich es verstehe, bedeutet dies, dass wir std::atomic<UDT>, wenn die folgenden true zurück verwenden können:

std::is_trivially_copyable<UDT>::value 

Nach dieser Logik sollten wir nicht in der Lage sein std::string als Template-Argument zu verwenden, für std::atomic und habe es richtig funktionieren.

jedoch der folgende Code kompiliert und läuft mit erwarteten Ausgang:

#include <atomic> 
#include <thread> 
#include <iostream> 
#include <string> 

int main() 
{ 
    std::atomic<std::string> atomicString; 

    atomicString.store("TestString1"); 

    std::cout << atomicString.load() << std::endl; 

    atomicString.store("TestString2"); 

    std::cout << atomicString.load() << std::endl; 

    return 0; 
} 

Ist dies ein Fall von undefiniertem Verhalten, das passiert einfach wie erwartet zu verhalten?

Vielen Dank im Voraus!

+1

Was ist Ihr Compiler (und Ihre Implementierung der Stdlib)? Ich konnte es nicht Compiler machen [hier] (http://coliru.stacked-crooked.com/view?id=0ce3b66093e9a0a59d5179429373eea7-e54ee7a04e4b807da0930236d4cc94dc), und das ist tatsächlich, was ich erwartet wurde –

+0

@AndyProwl Ich benutze VS 2012 bei der Moment, ohne den November CTP. –

+2

Wie Sie es verwenden, würde ich nicht erwarten, ein Problem zu sehen. Das Problem würde auftreten, wenn zwei (oder mehr) Threads versuchten, dieselbe Zeichenfolge gleichzeitig zu ändern. Zu diesem Zeitpunkt würde der nicht-triviale Operator von "string" anfangen, ein Problem zu verursachen. Wenn man etwas in "std :: atomic" einpackt, ist es wahrscheinlich nicht möglich, Code zu brechen, der ohne ihn in Ordnung wäre. Zur gleichen Zeit, ohne seinen Regeln zu folgen, wird es Code nicht helfen, der ohne es gebrochen würde. –

Antwort

38

Der Standard spezifiziert keine Spezialisierung von std::atomic<std::string>, so dass das generische template <typename T> std::atomic<T> gilt. 29.5 [atomics.types.generic] p1 states:

Es gibt eine generische Klassenvorlage atomare. Der Typ des Template-Arguments T soll trivial kopierbar sein (3.9).

Es gibt keine Aussage, dass die Implementierung Verletzungen dieser Anforderung diagnostizieren muss. Also entweder (a) ruft Ihre Verwendung von std::atomic<std::string> undefiniertes Verhalten auf oder (b) Ihre Implementierung stellt std::atomic<std::string> als eine konforme Erweiterung bereit.

auf der MSDN-Seite der Suche nach std::atomic<T> (http://msdn.microsoft.com/en-us/library/vstudio/hh874651.aspx), ist es ausdrücklich die Forderung erwähnen, dass trivialer kopierbar sein T, und es sagt nichts über spezifische std::atomic<std::string>. Wenn es sich um eine Erweiterung handelt, ist sie nicht dokumentiert. Mein Geld ist auf undefiniertes Verhalten.

Insbesondere gilt 17.6.4.8/1 (with thanks to Daniel Krügler for setting me straight):

In bestimmten Fällen (Ersatzfunktionen, handler Funktionen, Operationen auf Typen verwendeten Standardbibliothek Schablonenkomponenten instanziieren), der C++ Standard-Bibliothek hängt von Komponenten, die von einem C++ - Programm bereitgestellt werden. Wenn diese Komponenten nicht ihren Anforderungen entsprechen, stellt der Standard keine Anforderungen an die Implementierung.

std::string sicherlich erfüllt nicht die std::atomic<T> Anforderung, dass die Template-Parameter T trivialer kopierbar sein, so die Standard-Plätze keine Anforderungen an die Umsetzung. Beachten Sie als Qualität der Implementierung, dass static_assert(std::is_trivially_copyable<T>::value, "std::atomic<T> requires T to be trivially copyable"); eine einfache Diagnose ist, um diese Verletzung zu erfassen.


2016-04-19 Update: Ich weiß nicht, wann die Änderung passiert ist, aber VS2015 Update 2 jetzt std::atomic<std::string> nicht diagnostizieren:

error C2338: atomic requires T to be trivially copyable.
0

Warum Sie dies denken Sie "richtig" arbeiten, wenn mehrere Threads versuchen, die std::atomic<std::string> zu lesen/schreiben?

Das ist C++, Sie dürfen sich definitiv in den Fuß schießen. Wenn Sie einen Typ verwenden möchten, der nicht den Anforderungen entspricht, die Sie verwenden können, stoppt der Compiler "may" (nicht will!), Aber Sie werden seltsames/unerklärliches Verhalten zu einem bestimmten Zeitpunkt sehen, wenn mehrere Threads versuchen zu lesen/schreibe die Zeichenfolge.

Diese Anforderung dient zum Gewährleisten der Atomarität von Lese- und Schreibvorgängen. Wenn das Objekt nicht trivial kopierbar ist, dann visualisieren Sie diese Szene: Die Zeichenfolge hatte "Alter Wert". 1 Writer Probleme .store ("Neue Daten"), jetzt gibt es einen anderen Thread, der .load() auf die gleiche Variable, jetzt ohne eine trivially_copyable Eigenschaft, kann der Leser-Thread "Nld Value" oder "New Value" usw. sehen Es kann nicht atomar aktualisiert werden, daher die seltsamen Ergebnisse.

Da das von Ihnen gepostete Beispiel ein sequenzieller Code ist, passiert dies nicht.

6

Nein, dies ist ein undefiniertes Verhalten. Da darüber hinaus std :: string nicht trivialer kopierbar ist, sollten konforme Compiler ausgegeben haben „mindestens eine Diagnosemeldung“:

29,5 Atomtypen

Es ist eine generische Klassenvorlage atomar. Der Typ des Template-Arguments T soll trivial kopierbar sein (3.9).

1.4 Umsetzung Compliance

- Wenn ein Programm eine Verletzung von diagnostizierbaren enthält in der Regel [...] eine konforme Implementierung muss mindestens eine Diagnosemeldung aus.