Kiedy synchronizować wątki

0

Witajcie!

Mam pytanie dotyczące synchronizacji wątków. Jest to zagadnienie, którego dopiero się uczę, więc proszę o wyrozumiałość. Generalnie synchronizacja jest dla mnie zrozumiała, kiedy np. dwa wątki manipulują strukturą typu lista i wskaźnik może wskazywać coś, czego wcale nie chcemy i może to prowadzić nawet do wysypów aplikacji. Rozumiem też, kiedy np. odnosimy się do jednej zmiennej/struktury kilka razy w jednym wątku (nawet linijka po linijce), że stan faktyczny w poszczególnych przypadkach może być różny w zależności od tego, co robi inny wątek. Itd. itp. Nic odkrywczego.

Jednak co robić w takim prymitywnym przypadku: mamy przykładowo jedną zmienną typu int i dwa wątki - jeden zmienna wartość zmiennej, drugi odczytuje jej wartość:

// watek 1
while (aplikacja->dziala()) {
  // ...
  zmienna++; //zapis
  // ...
}
// watek 2
while (aplikacja->dziala()) {
  // ...
  cout<<zmienna; //odczyt - mniejsza z tym, czy przez cout czy w jakikolwiek inny sposób
  // ...
}

Umówmy się, że zmienna nie przekracza swej maksymalnej wartości wynikającej ze swojego typu, nie przekręca się licznik ani nie dzieją się żadne inne "dziwne rzeczy". Czy taki prosty przypadek również powinien być synchronizowany? Jeżeli nie, to co jeśli byłoby więcej wątków podobnych do wątku 1 albo wątku 2?

Wydawało mi się, że należy synchronizować wątki zawsze, kiedy jest prawdopodobieństwo wystąpienia jednoczesnego odczytu i zapisu jednej danej. Próbowałem jednak zasymulować taką sytuację (zarówno na procesorze jedno- jak i dwurdzeniowym) i nie udało mi się wysypać programu (myślałem, że ciągle jest takie zagrożenie). Przeprowadzałem długotrwałe testy i nic. Czy w takim przypadku rzeczywiście nie wydarzy się nic strasznego dla aplikacji, czy miałem po prostu dużo szczęścia?

Dziękuję z góry za odpowiedź.

Pozdrawiam,
Maurycy

0

Logika wskazuje, że gdy jeden wątek zapisuje zmienną, a reszta tylko czyta synchronizacja nie jest potrzebna. Jednakże praktyka pokazuje co innego. Do tego jeszcze jeśli będziesz rozwijał program i nagle będziesz jednak zmieniać wartość zmiennej w innych wątkach to możesz mieć kłopoty. Dlatego najbezpieczniej jest synchronizować wszystkie współdzielone zmienne!
Najprościej i najbezpieczniej jest napisać akcesory i rożne operacje dla współdzielonych zmiennych.
Np coś w tym stylu:

setZmienna(typ wartosc) {
    lock();
    zmienna = wartosc;
    unlock(); 
}

typ Zmienna() {
     lock()
     typ wynik = zmienna;
     unlock();
     return wynik;
}

typ powieksz() {
    lock();
    typ wynik = ++zmienna;
    unlock();
    return wynik;
}

Zwróć uwagę, że poniższy kod będzie nieprawidłowy (ze względu na wielowątkowość):

setZmienna(Zmienna()+1);

dlatego właśnie metoda powieksz jest konieczna.

A moja ogólna rada jest taka: dopóki nie nauczysz się porządnie programować normalnie (bez wielowątkowości), to nawet nie bierz się za wielowątkowość. Namieszasz sobie tylko w głowie, natracisz nerwów szukając przedziwnych błędów. Najpierw zdecydowanie należy nabyć dyscypliny utrzymania kodu (dobrego stylu), zanim zacznie się bawić w wielowątkowość.
Sam unikam wielowątkowości jeśli tylko jest to możliwe.

1 użytkowników online, w tym zalogowanych: 0, gości: 1