2017-10-12 1 views
6

So habe ich eine einfache cow_ptr. Es sieht etwa so aus:Kopieren am Schreiben mit shared_ptr

template<class T, class Base=std::shared_ptr<T const>> 
struct cow_ptr:private Base{ 
    using Base::operator*; 
    using Base::operator->; 
    using Base::operator bool; 
    // etc 

    cow_ptr(std::shared_ptr<T> ptr):Base(ptr){} 

    // defaulted special member functions 

    template<class F> 
    decltype(auto) write(F&& f){ 
    if (!unique()) self_clone(); 
    Assert(unique()); 
    return std::forward<F>(f)(const_cast<T&>(**this)); 
    } 
private: 
    void self_clone(){ 
    if (!*this) return; 
    *this = std::make_shared<T>(**this); 
    Assert(unique()); 
    } 
}; 

dies garantiert, dass es einen nicht-const T hält und sichert es unique ist, wenn es .write([&](T&){}) s zu.

Die Abwertung von .unique() scheint darauf hinzuweisen, dass dieses Design fehlerhaft ist.

Ich vermute, dass, wenn wir mit einem cow_ptr<int> ptr mit 1 in Thread A zu starten, geben sie B einzufädeln, es einzigartig machen, ändern Sie es zu 2, es ptr zurück und haben passieren lesen es in thread A wir ein Rennen erzeugt Bedingung.

Wie behebe ich das? Kann ich einfach eine Speicherbarriere in write hinzufügen? Welcher? Oder ist das Problem grundlegender?

Sind die Symptome auf x86 aufgrund der x86-Speicherkonsistenz, die über C++ hinausgeht, weniger wahrscheinlich?

Antwort

0

Ich denke, die Idee, dies zu mißbilligen ist, dass es nicht falsch wie verwendet werden kann, wenn man Code wie folgt hat:

if(sp.unique()) { 
    // some deinitialisation 
} else { 
    // somebody else will deinitialise. 
} 

Es ist möglich, dass es dann deinitialise fehlschlagen, wenn es laufen geschieht 2 mal gleichzeitig.

In Ihrem speziellen Fall, dass ich kein Problem sehen, weil

  1. wenn es nicht einzigartig war und wurde einzigartig - es ist keine große Sache ist, werden Sie nur zusätzliche Kopie machen
  2. wenn es war einzigartig und nicht eindeutig wurde, dann denken Sie ändern und das Kopieren die gleiche Instanz in zwei verschiedenen Threads (was ein Problem sowieso sein wird)

ich nicht, dass es mit dem Befehl, anderes Problem ist, da Zähler auf Speicher zuzugreifen, in shared_ptr werden atomar.

Ich würde wahrscheinlich nur auf use_count == 1 mit entsprechenden Kommentar

wechseln