2011-02-02 9 views
7

Poniższy fragment z obecnego projektu pokazuje, co to znaczy:C++ 0x | Dlaczego std :: atomic przeciąża każdą metodę za pomocą volatile-qualifier?

namespace std { 
    typedef struct atomic_bool { 
     bool is_lock_free() const volatile; 
     bool is_lock_free() const; 
     void store(bool, memory_order = memory_order_seq_cst) volatile; 
     void store(bool, memory_order = memory_order_seq_cst); 
     bool load(memory_order = memory_order_seq_cst) const volatile; 
     bool load(memory_order = memory_order_seq_cst) const; 
     operator bool() const volatile; 
     operator bool() const; 
     bool exchange(bool, memory_order = memory_order_seq_cst) volatile; 
     bool exchange(bool, memory_order = memory_order_seq_cst); 
     bool compare_exchange_weak(bool&, bool, memory_order, memory_order) volatile; 
     bool compare_exchange_weak(bool&, bool, memory_order, memory_order); 
     bool compare_exchange_strong(bool&, bool, memory_order, memory_order) volatile; 
     bool compare_exchange_strong(bool&, bool, memory_order, memory_order); 
     bool compare_exchange_weak(bool&, bool, memory_order = memory_order_seq_cst) volatile; 
     bool compare_exchange_weak(bool&, bool, memory_order = memory_order_seq_cst); 
     bool compare_exchange_strong(bool&, bool, memory_order = memory_order_seq_cst) volatile; 
     bool compare_exchange_strong(bool&, bool, memory_order = memory_order_seq_cst); 
     atomic_bool() = default; 
     constexpr atomic_bool(bool); 
     atomic_bool(const atomic_bool&) = delete; 
     atomic_bool& operator=(const atomic_bool&) = delete; 
     atomic_bool& operator=(const atomic_bool&) volatile = delete; 
     bool operator=(bool) volatile; 
    } atomic_bool; 
} 

Lotny jest przechodnia. W związku z tym nie można wywołać nielotnej funkcji składowej z obiektu zmiennego. Z drugiej strony dozwolone jest wywoływanie funkcji zmiennej z obiektu nieulotnego.

Czy istnieje zatem różnica w implementacji między lotnymi i nielotnymi funkcjami członków w klasach atomowych? Innymi słowy, czy istnieje potrzeba trwałego przeciążenia?

+0

Lepsze pytanie brzmi: dlaczego w pierwszej kolejności muszą występować przeciążenia 'volatile'. – GManNickG

+1

@GMan: ponieważ w przeciwnym razie funkcje nie mogły zostać wywołane na lotnych danych. ;) – jalf

+3

@jalf: Ha, tak, ale skoro operacje, które sam tworzy, są atomowe (a więc i obserwowalne), dlaczego mielibyśmy stworzyć 'lotny atomowy <>? Chyba brakuje mi czegoś poważnego. – GManNickG

Odpowiedz

4

Myślę, że lotne przeciążenia istnieją ze względów wydajnościowych. Niestabilne odczyty i zapisy są z natury droższe niż nieulotne odczyty i zapisy w C++ 0x, ponieważ model pamięci stawia pewne rygorystyczne wymagania, które zapobiegają buforowaniu wartości zmiennych zmiennych. Jeśli wszystkie funkcje były oznaczone jako niestabilne, kod niekoniecznie musiałby dokonać pewnych optymalizacji, które w przeciwnym razie poprawiłyby wydajność. Posiadanie rozróżnienia umożliwia kompilatorowi optymalizację nieulotnych odczytów i zapisów, o ile jest to możliwe, przy jednoczesnym poniżeniu z wdziękiem, gdy wymagane są ulotne odczyty i zapisy.

+1

Kwalifikator lotny po prostu zapobiega optymalizacji kompilatora. Ponadto, o ile wiem, lotny kwalifikator zastosowany do funkcji członkowskich pozwala tylko na wywołanie tej metody z obiektów lotnych i nie wpływa na wynikowy kod. – 0xbadf00d

+4

@ FrEEzE2046- W C++ 0x definicja 'volatile' jest dużo bardziej sztywno określona i ma na myśli coś więcej niż" nie optymalizuj ". Ponadto, bardziej precyzyjne znaczenie lotnego modyfikatora w funkcji składowej jest takie, że "ten" wskaźnik jest "zmienny", a więc każdy dostęp do zmiennych członkowskich, które występują w funkcji, stałby się domyślnie niestabilny. – templatetypedef

+0

OK, oznacza to dostęp do obiekt, wywołując funkcję zmiennej członek, nie zostałaby zoptymalizowana? (Niestabilny opis to: "Dostęp do obiektów lotnych jest oceniany ściśle według reguł maszyny abstrakcyjnej.") – 0xbadf00d

-1

Po pierwsze, brzmi to zbędnie, aby stworzyć niestabilny std :: atomowy. Właściwie mogę sobie wyobrazić przydatną sytuację. Zakładając, że mamy stały adres urządzenia (pamięci), na którym chcemy działać. Z uwagi na to, że klasy std :: atomic_xxx oraz std :: atomic <> wielkości klas szablonów powinny być tej samej wielkości co ich wbudowane typy, możesz chcieć obsłużyć oba: Wykonywanie operacji atomowych z kontrolą nad zamawianie pamięci i upewnij się, że dostęp do naszego obiektu atomowego nigdy nie jest zoptymalizowany. Tak więc możemy zadeklarować coś takiego:

std::atomic<long> volatile* vmem_first4 = reinterpret_cast<std::atomic<long> volatile*>(0xxB8000); 
+0

Standard wyraźnie mówi, że 'atomowy ' może nie mieć tego samego rozmiaru co odpowiednik 'T' – jalf

+1

" Reprezentacja typu adresu atomowego nie musi mieć tego samego rozmiaru co odpowiadający mu typ regularny. możliwy." Tak więc, lotny atom atomowy wydaje mi się bezużyteczny. – 0xbadf00d

Powiązane problemy