Panel użytkownika
Nazwa użytkownika:
Hasło:
Nie masz jeszcze konta?

[C++] std::atomic, a działanie std::memory_order_relaxed

Ostatnio zmodyfikowano 2013-06-05 12:27
Autor Wiadomość
fers334
Temat założony przez niniejszego użytkownika
[C++] std::atomic, a działanie std::memory_order_relaxed
» 2013-06-02 10:30:43
Witam mam problem , a mianowicie to że nie wiem dlaczego program nie działa tak jak powinien.
Oto program :

C/C++
#include <atomic>
#include <thread>
#include <assert.h>

std::atomic < bool > x, y;
std::atomic < int > z;

void write_x_then_y()
{
    x.store( true, std::memory_order_relaxed );
    y.store( true, std::memory_order_relaxed );
}
void read_y_then_x()
{
    while( !y.load( std::memory_order_relaxed ) );
   
    if( x.load( std::memory_order_relaxed ) )
         ++z;
   
}

int main()
{
    x = false;
    y = false;
    z = 0;
   
    std::thread a( write_x_then_y );
    std::thread b( read_y_then_x );
    a.join();
    b.join();
    assert( z.load() != 0 );
   
}

Problem jest w tym , że podczas ustawienia porządkowania złagodzonego funkcja assert powinna móc wskazać błąd ponieważ operacja ładowania zmiennej x może odczytac false,lecz w moim programie do tego nie dochodzi, zawsze zostaje odczytana wartość true.W książce jest dokładnie ten przykład wiec nie mam pojęcia dlaczego mimo stosowania tego sposobu porządkowania zawsze x odczytuje true.Prosze o pomoc.
P-84609
pekfos
» 2013-06-02 13:01:05
operacja ładowania zmiennej x może odczytac false
Wątek a najpierw zapisuje x, a potem y. Wątek b czeka, aż y będzie ustawione na true, a wtedy x też będzie ustawione na true, więc z zostaje zwiększone. z będzie inne od zera, więc asercja nie zakończy programu.
P-84625
fers334
Temat założony przez niniejszego użytkownika
» 2013-06-02 14:38:25
Właśnie ja tez to tak rozumiem lecz w książce którą posiadam jest napisane tak :


asercja może wykazać błąd, ponieważ operacja ładowania zmiennej x może odczytac wartość false ,nawet jeśli operacja ładowania zmiennej y odczyta wartosc true i jesli operacja zapisu zmiennej x miała miejsce przed operacja zapisu zmiennej y.x i y to dwie różne zmienne , zatem widoczność wartości odczytywanych za pośrednictwem operacji na tych zmiennych nie podlega żadnym regułom i ograniczeniom kolejnosci.
P-84644
fers334
Temat założony przez niniejszego użytkownika
» 2013-06-04 20:42:39
Rozumiem że nikt nie potrafi pomóc mi w nurtującej mnie sprawie, skoro tak to zamykam temat
oraz dziękuje za próbę udzielenia pomocy.

Fers
P-84863
DejaVu
» 2013-06-04 21:39:59
Skoro jesteś w gorącej wodzie kąpany... to trudno :) Ja przeglądam ostatnio tylko tematy nieaktywne dłużej niż 3 dni :)

PS.

C/C++
void write_x_then_y()
{
    x.store( true, std::memory_order_relaxed ); //2. ta linijka wykona się zawsze (niezależnie kiedy będzie uruchomiony wątek)
    y.store( true, std::memory_order_relaxed ); //4. a ta linijka zapewnia, że zawsze linijka '1.' będzie czekała na aż się 'zakończy' wywołanie write_x_then_y
}
void read_y_then_x()
{
    while( !y.load( std::memory_order_relaxed ) ); //1. ta linijka zawsze będzie czekała tak długo jak długo Y jest false, więc....
   
    if( x.load( std::memory_order_relaxed ) ) //3. Skoro linijka '2.' zawsze się wykona, to ten warunek będzie zawsze spełniony
         ++z;
   
}

PSS.
http://en.cppreference.com/w/cpp/atomic/atomic

Each instantiation and full specialization of the std::atomic template defines an atomic type. Objects of atomic types are the only C++ objects that are free from data races; that is, if one thread writes to an atomic object while another thread reads from it, the behavior is well-defined.

PSSS. Jeżeli czytasz polską książkę, to nie dziw się, że mogą być bezsensowne zdania, bo takie książki są z definicji tłumaczone, a nie pisane przez osobę techniczną.

/edit:
Dodam jeszcze:
http://en.cppreference.com/w/cpp/atomic/memory_order

Atomic operations tagged std::memory_order_relaxed are not synchronization operations, they do not order memory. They only guarantee atomicity and modification order consistency.
For example, with x and y initially zero,
C/C++
// Thread 1:
r1 = y.load( memory_order_relaxed ); // A
x.store( r1, memory_order_relaxed ); // B
// Thread 2:
r2 = x.load( memory_order_relaxed ); // C
y.store( 42, memory_order_relaxed ); // D
is allowed to produce r1 == r2 == 42 because, although A is sequenced-before B and C is sequenced before D, nothing prevents D from appearing before A in the modification order of y, and B from appearing before C in the modification order of x.
Updating the same global counter from multiple threads requires atomicity, but no synchronization or ordering
Więc operacje w każdym wątku są wykonywane sekwencyjnie, a jedynie nie ma gwarancji w którym momencie będą wykonywane dane linijki z każdego wątku (ale kolejność wykonywania linijek w każdym wątku jest znana).
P-84878
DejaVu
» 2013-06-04 22:07:37
Hm...

The rationale of this is that when several threads simultaneously read and write to several variables on multi-core systems, one thread might see the values change in different order than another thread has written them.
Te różne tryby atomica faktycznie warto przestudiować... może w tej książce rację mają...? :P

/edit:
Ja bym eksperymentalnie zapuścił np. milion razy wykonanie tego kodu i sprawdził czy choć raz zachodzi Assert. Trochę jeszcze poczytałem na ten temat i... koniec końców najlepszym rozwiązaniem byłoby wzięcie kartki oraz rozpisanie każdego 'memory_order' tak, aby zauważyć i zrozumieć pomiędzy nimi różnice.


/edit2:
W każdym razie wydaje mi się nieco dziwne, aby zmienna modyfikowana później była 'synchronizowana' przed zmienną modyfikowaną wcześniej w tym samym wątku więc... coś tu się kupy zbytnio nie trzyma :)
P-84883
fers334
Temat założony przez niniejszego użytkownika
» 2013-06-04 22:21:46
Wielkie dzięki no to zacznę kombinować.Jeszcze raz dzięki.
P-84885
DejaVu
» 2013-06-04 22:27:38
Spoko, no ale poteoretyzujmy skoro taki ciekawy temat się trafił :P
Załóżmy, że wykonam instrukcję A (modyfikuje x) i B (modyfikuje y). Drugi wątek wisi na instrukcji C (czyta y), więc w celu pójścia dalej musi albo poczekać na synchronizację albo wymusić ją. Więc jeżeli załóżmy wątek wymusi synchronizację tej jednej zmiennej (bo bez tego dalej nie pójdzie), to uzyskamy sytuację, w której wątek drugi widzi modyfikację instrukcji B ale nie widzi modyfikacji instrukcji A. Jednak później jest linijka odpytująca się o stan zmiennej x, więc teoretycznie powinno pójść wymuszenie synchronizacji instrukcji A. Jednak jeżeli zmienna podczas odczytywania nie wymusza synchronizacji to powstaje pytanie KTO decyduje o tym, kiedy nastąpi synchronizacja stanów zmiennych?

Wydaje mi się, że nie powinno dojść do sytuacji, w której zmienna modyfikowana później jest synchronizowana przed zmienną modyfikowaną wcześniej w tym samym wątku... bo gdzie tu jakiś sensowny determinizm, który można wykorzystać przy kodowaniu?
P-84886
« 1 » 2
  Strona 1 z 2 Następna strona