2015-11-15 5 views
5

Ich schreibe einen Kopierkonstruktor für eine Datenstruktur, die zwei std::atomic<T> Mitglieder in ein neues Objekt kopieren muss. Während der Prozess in meinem Anwendungsfall nicht notwendigerweise atomar sein muss, würde ich es vorziehen, die bestmögliche Lösung zu haben.Nicht blockierende Möglichkeit zum Kopieren von Atomics im Kopierkonstruktor

Ich bin mir bewusst, dass der Kopierkonstruktor explizit mit std::atomic<T> gelöscht wird, um Benutzer zu zwingen, die atomare Schnittstelle zu verwenden.

atomar (const atomic &) = löschen;

Was ich gerade ich so etwas wie dies tue:

SomeObject(const SomeObject& other): 
    _atomic1(other._atomic1.load()),    
    _atomic2(other._atomic2.load()) { 
... 
} 

Ich glaube nicht, dass diese Operation atomar ist, noch weiß ich, ein Weg, dies zu machen ist (ohne Schleusen).

Gibt es eine Möglichkeit, diese Werte atomar (ohne Sperren) zu kopieren?

+0

Es gibt keine allgemeine Möglichkeit, zwei zufällige atomare Objekte atomar zu kopieren, wenn Sie das fragen. Fügen Sie einen Mutex hinzu, wenn Sie tatsächlich eine Atombombe benötigen. –

+3

9 mal von 10, wird die Antwort auf diese Frage sein "Sie müssen das nicht tun. Sie gehen über was auch immer Sie den falschen Weg machen". Wenn die Datenstruktur zum Beispiel eine Art von Sammlung ist, dann wird sie bereits eine Möglichkeit haben, ihren Inhalt in einer gleichrangigen Weise zu erhalten, und Sie sollten diese verwenden. –

+0

@MattTimmermans Das ist ein toller Punkt, obwohl meine Frage akademischer Natur ist. ** Zuschauer dieser Frage sollten, wenn möglich, die von Experten entwickelten Typen zur Kenntnis nehmen und verwenden. ** Nebenläufigkeit ist schwierig. Wenn Sie also selbst etwas schreiben, sollten Sie es einem Peer-Review unterziehen. –

Antwort

4

Die einzige Möglichkeit besteht darin, eine trivial kopierbare Struktur S mit zwei T s zu erstellen und std::atomic<S> zu verwenden.

Beachten Sie, dass dies nur funktioniert, wenn Sie diese S von Anfang an verwendet haben - es gibt keine Möglichkeit, zwei separate Atomics ohne Sperren zu laden.

Also statt:

struct SomeObject { 
    SomeObject(const SomeObject& other) : i(other.i.load()), j(other.j.load()) { } 
    std::atomic<int> i, j; 
}; 

tun:

struct SomeObject { 
    SomeObject(const SomeObject& other) : data(other.data.load()) { } 
    struct Data { int i, j; }; 
    std::atomic<Data> data; 
}; 

Beachten Sie, dass dies könnte (wahrscheinlich) noch intern Schlösser verwenden. Verwenden Sie is_lock_free, um zu überprüfen, ob dies der Fall ist.

+0

Hmm. Das ist kreativ, aber ich vermute, dass es interne Sperren verwendet. Ich werde es ausprobieren. –

+0

@DonScott [Für <= 64 Bit-Strukturen scheint es frei von Sperren zu sein, aber nicht größer.] (Http://coliru.stacked-crooked.com/a/e496ba55f9a710a8) – orlp

+0

Ich habe das gleiche Ergebnis, aber Zuschauer sollten dies beachten ** Dieses Verhalten ist abhängig vom Compiler und der Architektur. ** Ausgerichtet 8 Byte Lese-/Schreibzugriffe sind im Allgemeinen atomar auf aktueller Hardware (selbst auf 32-Bit-Betriebssystemen), aber Benutzer sollten darauf achten, ihre Systeme zu verifizieren. –

Verwandte Themen