Wpis z mikrobloga

Mam pytanie odnośnie #cplusplus i #programowanie wielowątkowe. Dla ustalenia uwagi załóżmy że kompilator to linuksowe g++, a wątki są z biblioteki z c++11, chociaż to pewnie żadna różnica.

Do tej pory zawsze kompilowałem programy wielowątkowe bez żadnej optymalizacji i wszystko śmigało. Dołożenie flagi -02 może zepsuć działający kod przez optymalizacje kodu, najprostszy przykład:

int a=0 ; // zmienna globalna z której wszyscy będą korzystać
... ; while(!a) {} ; ... // watek1
... ; a=1 ; ... // watek 2
I teraz aktywne oczekiwanie z wątku nr 1 może zostać zwinięte przez kompilator do wyrażenia postaci:

if(!a) for(;;) {}
bo kompilator z punktu widzenia jednowątkowej kompilacji nie ma pojęcia, że zmienna może się zmienić pomiędzy odczytami. Rozwiązanie tego problemu to dołożenie volatile do definicji zmiennej a.

Po tym przydługim wstępie zarysującym problem pora na moje rozkminy. Załóżmy że mamy jakąś sekcję krytyczną, dostęp do zmiennych, które za każdym razem obstawiamy mutexami z . Czy wszystkie zmienne też muszą być zdefiniowane jako volatile ? W sensie czy istnieje jakis kod w stylu:

m.lock() ;
... // sekcja krytyczna, dostep do zmiennych
m.unlock() ;

w którym jeśli użyte zmienne nie będą volatile, to kompilator z flagą O2 może sobie zrobić takie optymalizacje, które zepsują wielowątkowy program?

#kiciochpyta
  • 12
  • Odpowiedz
  • Otrzymuj powiadomienia
    o nowych komentarzach

@dasdadas4: 1) używanie zmiennych globalnych, szczególnie w aplikacji wielowątkowej będzie się mścić
2) Pozbądź się zmiennych globalnych, pozbędziesz się problemu z optymalizacjami....
  • Odpowiedz
@dasdadas4: Niezabezpieczony zapis i odczyt zmiennej z dwóch wątków to undefined behaviour, więc kod był błędny od samego początku. Volatile nie ma nic wspólnego z wielowątkowością.

kompilator z flagą O2 może sobie zrobić takie optymalizacje, które zepsują wielowątkowy program?


Nie może. Twój program się zepsuł, bo miał
  • Odpowiedz
@alex-fortune: tak, ale jak je wykorzystasz w odpowiedniej funkcji, która będzie zarządzać zmienną widzianą tylko w jednym module, to nie będziesz miał g*no kodu, którego strach dotknąć, bo coś zaraz się spierdzieli, bo gdzieś indziej, ktoś tą zmienną wykorzystał inaczej.
  • Odpowiedz
@dasdadas4: jeśli potrzebujesz zmienną to zamykasz ją w jednym module jako zmienna statyczna, dostęp do niej robisz za pomocą funkcji, które udostępniasz i tam dbasz o to aby było bezpiecznie wywołane z różnych wątków.
  • Odpowiedz
Niezabezpieczony zapis i odczyt zmiennej z dwóch wątków to undefined behaviour, więc kod był błędny od samego początku


@ponton: cóż, to miał być przykład gdy kompilator może coś zepsuć, a nie mój faktyczny program. W moim faktycznym programie to odczyt/zapis do współdzielonych zmiennych mutexami obłożę mutexami - i pytam czy wtedy kompilator nadal może zrobić jakąś optymalizacyjną sztuczkę, która coś zepsuje
  • Odpowiedz
@dasdadas4: tak jak w linku który przytoczył @asciiterror w C++11 bezpieczny dostęp z wielu wątków to tylko
poprzez zmienną std::atomic
A co do synchronizacji to prócz mutexu do takich żeczy używa się conditonal_varible, albo poprostu semaforów.
  • Odpowiedz
@lionbest: @ponton: może nie widać z tego wpisu, ale ja rozumiem czym są zmienne atomowe, mutexy, zmienne warunkowe, teoretyczne modele synchronizacji... Pytanie dotyczyło możliwych optymalizacji przez kompilator. Np czy kompilator mógłby zwinąć coś takiego:

m.lock()
a
  • Odpowiedz