2015-06-10 12 views
17

Mam klasy, że wan go używać w różnych wątków i myślę, że mogę być w stanie wykorzystać std::atomic takie jak to:jak używać std :: atomowej <>

classs A 
{ 
    int x; 

public: 
    A() 
    { 
     x=0; 
    } 

    void Add() 
    { 
     x++; 
    } 

    void Sub() 
    { 
     x--; 
    }  
}; 

iw moim kodu :

std::atomic<A> a; 

w różnych nici:

a.Add(); 

i

a.Sub(); 

, ale gdy otrzymuję komunikat o błędzie, nieznana jest nazwa a.Add(). Jak mogę to osiągnąć?

Czy istnieje lepszy sposób to zrobić?

Edycja 1

Należy pamiętać, że jest to próbka przykład, i to, co chcę jest, aby upewnić się, że dostęp do klasy A jest threadsafe, więc nie mogę używać

std::atomic<int> x; 

Jak mogę uczynić wątek klasy bezpiecznym przy użyciu std :: atomic?

+2

Zobacz poradnik http://baptiste-wicht.com/posts/2012/07/c11-concurrency-tutorial-part-4-atomic-type.html. – user1929959

Odpowiedz

4

stwierdzenie X członek klasy jako atomowy, to nie trzeba zadeklarować obiekt jako atomowej

class A 
{ 
    std::atomic<int> x; 
} 
+1

@mans Możesz bezpiecznie uzyskać dostęp do różnych elementów 'std :: vector' z wielu wątków, o ile nie masz dostępu do tego samego elementu z kilku wątków. To gwarancja standardowej biblioteki. – Morwenn

+1

@Morwenn Ale wydaje się, że nie mogę pisać. Jeśli czytam w jednym wątku i piszę w innym wątku, system zawiesza się, czy jestem w błędzie? – mans

24

Trzeba uczynić x przypisują atomowej, a nie całą swoją klasę, jak następuje:

class A 
{ 
    std::atomic<int> x; 

    public: 
     A() { 
     x=0; 
     } 
     void Add() { 
     x++; 
     } 
     void Sub() { 
     x--; 
     }  
}; 

błąd masz w sobie oryginalny kod jest całkowicie normalny: nie ma std::atomic<A>::Add metoda (patrz here), chyba że dostarczenie specjalizacji dla std::atomic<A>.

Odnosząc edycję: magicznie nie można dokonać wątek class A bezpieczne używając go jako szablonu argumentu std::atomic. Aby uczynić ją bezpieczną dla wątków, możesz uczynić jej atrybuty atomowymi (jak sugerowano powyżej i pod warunkiem, że biblioteka standardowa nadaje im specjalizację), lub użyć muteksów, aby samemu zablokować zasoby. Zobacz nagłówek mutex. Na przykład:

class A 
{ 
    std::atomic<int>  x; 
    std::vector<int>  v; 
    std::mutex   mtx; 

    void Add() { 
    x++; 
    } 
    void Sub() { 
    x--; 
    } 

    /* Example method to protect a vector */ 
    void complexMethod() { 
    mtx.lock(); 

    // Do whatever complex operation you need here 
    // - access element 
    // - erase element 
    // - etc ... 

    mtx.unlock(); 
    } 

    /* 
    ** Another example using std::lock_guard, as suggested in comments 
    ** if you don't need to manually manipulate the mutex 
    */ 
    void complexMethod2() { 
    std::lock_guard<std::mutex> guard(mtx); 

    // access, erase, add elements ... 
    } 

}; 
+8

Proponuję 'std :: lock_guard' zamiast ręcznego blokowania i zwalniania. –

+0

@LukeB. Zmieniono, dziękuję za sugestię. – Unda

+1

@ LukeB. Czy idea lock_guard polega na wykorzystaniu destruktorów zmiennych automatycznych, które mają zostać wywołane podczas wychodzenia z zakresu w celu zwolnienia blokady, tak jak w przypadku RAII? – Virus721

3

Operator . może być stosowany na obiekt, aby wywołać funkcję składową swojej klasie, a nie funkcję składową jakiejś innej klasy za (chyba że wyraźnie napisać kod w ten sposób).

std::atomic<A> a ; 
a.Add(); // Here, a does not know what Add() is (a member function of the type parameter) 
     // It tries to call Add() method of its own class i.e. std::atomic 
     // But std::atomic has no method names Add or Sub 

Jako odpowiedź przez @ivanw wspomina, należy std::atomic<int> członkiem klasy zamiast a następnie użyć go.

Oto kolejny przykład:

template <typename T> class A 
{}; 

class B { public: void hello() { std::cout << "HELLO!!!"; } }; 

A<B> a ; 
a.hello(); // This statement means that call a's hello member function 
      // But the typeof(a) which is A does not have such a function 
      // Hence it will be an error. 
0

Myślę, że problem z powyższych odpowiedzi jest, że nie wyjaśnić, co moim zdaniem jest, co najmniej, niejednoznaczność w pytaniu, a najprawdopodobniej, wspólny wątły błąd rozwojowy.

Nie można uczynić obiektu "atomowym", ponieważ przerwa między dwiema funkcjami (najpierw "odczyt x", a potem "zapis x") spowoduje wyścig z innymi zastosowaniami. Jeśli uważasz, że potrzebujesz "atomowego" obiektu, musisz dokładnie zaprojektować interfejs API i funkcje składowe, aby udostępnić je teraz i rozpocząć aktualizację obiektu.

Jeśli wszystko, co masz na myśli, mówiąc "atomowy", to "obiekt nie zakłóca stanu wewnętrznego", możesz to osiągnąć przez std::atomic<> dla pojedynczych, zwykłych, starych typów danych, które nie mają między sobą żadnych niezmienników (a nie " t zależy od b), ale potrzebujesz jakiejś blokady dla jakichkolwiek zależnych reguł, które musisz wymusić.

Powiązane problemy