2013-05-23 20 views
7

Zastanawiam się, czy tylko podstawowe typy danych mogą być std :: atomowe w C++ 11? Czy można na przykład zadeklarować, że obiekt klasy bibliotecznej zostanie "atomowo" zmutowany lub uzyskany dostęp?C++ 11 Czy tylko pierwotne typy danych mogą być zadeklarowane jako atomowe?

Na przykład może mam

using namespace std::chrono; 
time_point<high_resolution_clock> foo; 

// setter method 
void set_foo() { 
    foo = high_resolution_clock::now(); 
} 

// getter method 
time_point<high_resolution_clock> get_foo() { 
    return foo; 
} 

Ale jeśli te metody setter i getter są nazywane w różnych wątkach, myślę, że może spowodować niezdefiniowane zachowanie. Byłoby miło, gdybym mógł zadeklarować foo coś takiego:

std::atomic<time_point<high_resolution_clock>> foo; 

... tak, że wszystkie operacje na foo będzie prowadzona w sposób atomowej. W zgłoszeniu do mojego projektu jest prawdopodobnie setki takich zmiennych foo zadeklarowanych na kilkudziesięciu klasach i wydaje mi się, że byłoby znacznie wygodniej dokonać mutacji obiektu i dostępu do "atomowej", że tak powiem, zamiast deklarować i lock_guard muteksuje w każdym miejscu.

Czy to nie jest możliwe, czy jest lepsze podejście, czy też naprawdę muszę używać muteksu i lock_guarda wszędzie?

Aktualizacja:

  • Wszelkie chętnych? Szukałem przyzwoitej informacji w Internecie, ale jest tak mało przykładów użycia atomu, że nie jestem pewien, w jakim stopniu można go zastosować.
+0

std :: atomic nie zastępuje złamanego kodu wątku. Jeśli inny wątek wywoła program ustawiający, to niezależnie od tego, co pierwszy wątek go wywoła, i tak otrzyma wartość śmieci od gettera. –

Odpowiedz

3

atomic<> nie jest ograniczony do typów pierwotnych. Dozwolone jest użycie atomic<> z typem T, który jest trivially copyable. Z sekcji 29,5 typy atomowe o standard C++ 11 (również wyceniane std::atomic):

Jest to ogólna klasa szablon atomowej. Typ szablonu argumentu T można trywialnie kopiować (3.9).

przypadku obiektów, dla których jest wymagany dostęp atomowej nie może być stosowany z atomic<> następnie definiowania nowych obiektów, zawierające oryginalnego przedmiotu i std::mutex. Oznacza to, że lock_guard<> jest używany wewnątrz gettera i ustawiacza tylko dla nowego obiektu bezpiecznego wątku, a nie zaśmiecany w całym kodzie. template może być w stanie określić maszynerię bezpieczeństwa wymagany gwint:

template <typename T> 
class mutable_object 
{ 
public: 
    mutable_object() : t_() {} 
    explicit mutable_object(T a_t) : t_(std::move(a_t)) {} 
    T get() const 
    { 
     std::lock_guard<std::mutex> lk(mtx_); 
     return t_; 
    } 
    void set(T const& a_t) 
    { 
     std::lock_guard<std::mutex> lk(mtx_); 
     t_ = a_t; 
    } 
private: 
    T t_; 
    mutable std::mutex mtx_; 
}; 

using mutable_high_resolution_clock = 
     mutable_object<std::chrono::time_point< 
      std::chrono::high_resolution_clock>>; 

using mutable_string = mutable_object<std::string>; 

mutable_high_resolution_clock c; 
c.set(std::chrono::high_resolution_clock::now()); 
auto c1 = c.get(); 

mutable_string s; 
s.set(std::string("hello")); 
auto s1 = s.get(); 
0

Atomics są ograniczone do trywialnie copyable klasy (czyli klas, które nie mają własnego konstruktor kopiujący i których członkami są również trywialnie copyable).

Wymóg ten ma ogromne korzyści dla atomistyki:

  • No operacja atomowa może rzucać, ponieważ konstruktor rzucił
  • Wszystkie atomowe mogą być modelowane z zamkiem (Spinlock lub mutex) i memcpy skopiować dane.
  • Wszystkie atomics mają skończony czas działania (ograniczony).

Ten ostatni jest szczególnie przydatny, ponieważ atomiki są czasem implementowane za pomocą spinlocków i bardzo pożądane jest unikanie nieskojarzonych zadań przy jednoczesnym utrzymywaniu blokady spinlock. Jeśli którykolwiek z konstruktorów byłby dozwolony, implementacje musiałyby powracać na pełnych muteksach, które są wolniejsze od spinlocków dla bardzo małych sekcji krytycznych.

Powiązane problemy