2017-10-12 26 views
6

Tak więc mam prosty cow_ptr. Wygląda to mniej więcej tak:Kopiuj przy użyciu funkcji udostępnionej

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()); 
    } 
}; 

to gwarantuje, że posiada const T i zapewnia, że ​​jest unique gdy .write([&](T&){}) s do niego.

Wycofanie z .unique() wydaje się wskazywać, że ten projekt jest wadliwy.

Jestem zgadywania, że ​​jeśli zaczniemy z cow_ptr<int> ptr z 1 w wątku A, przekazać go do wątku B, uczynić go wyjątkowym, modyfikować je 2 przechodzą ptr go z powrotem i przeczytaj ją w wątku A mamy generowane wyścig stan.

Jak to naprawić? Czy mogę po prostu dodać barierę pamięci w numerze write? Który? A może problem jest bardziej fundamentalny?

Czy objawy są mniej prawdopodobne na x86 z powodu spójności pamięci x86 wykraczającej poza wymagania C++?

Odpowiedz

0

Myślę, że pomysł, aby potępiać to, że nie może być stosowany nieprawidłowo jak gdybyś miał kod tak:

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

Jest możliwe, że będzie to nie deinitialise jeśli zdarza się uruchomić 2 razy jednocześnie.

W danym przypadku nie widzę żadnego problemu, ponieważ

  1. gdyby nie wyjątkowy i stał się wyjątkowy - to nic wielkiego, będziesz po prostu zrobić dodatkową kopię
  2. jeśli to był wyjątkowy i nie stała się wyjątkowa, to zmienia i kopiowanie tego samego wystąpienia w dwóch różnych wątków (co będzie problemem w każdym razie)

nie sądzę, istnieje inny problem z rozkazem, aby uzyskać dostęp do pamięci od liczników w shared_ptr są atomowy.

Prawdopodobnie po prostu przełączyć na use_count == 1 może być z odpowiednim komentarzem