-
Data: 2013-07-02 19:56:21
Temat: Re: pytanie z mutexów
Od: Edek <e...@g...com> szukaj wiadomości tego autora
[ pokaż wszystkie nagłówki ]Dnia pamiętnego Tue, 02 Jul 2013 18:16:18 +0200, Michoo wyjmując peta
oznajmił:
> On 01.07.2013 19:08, Edek wrote:
>> Dnia pamiętnego Mon, 01 Jul 2013 18:24:17 +0200, Michoo wyjmując peta
>> oznajmił:
>>> Co do samego algorytmu - potrzebne są trzy stany:
>>> przed_inicjalizacją, w_trakcie, po_inicjalizacji, nie da się tego zrobić
>>> na JEDNEJ fladze binarnej, można by użyć dwóch(i wprowadzić odpowiednie
>>> poprawki), ale po co?
>>
>> Nie, jest potrzebna monotonicznie rosnąca liczba, nie trzy stany. Mi
>> to zajęło z pół godziny żeby dojść dlaczego: spróbuj zastąpić
>> monotonicznie rosnącą stanami i albo udowodnij poprawność
>> albo udowodnij że jest problem.
>
> #define START_VALUE 2
> #define BEING_INITIALIZED 1
> #define INIT_DONE 0
>
> /* PRECONDITION:
> *once == START_VALUE
> */
>
> void fast_pthread_once( fast_pthread_once_t *once, void (*func)(void) )
> {
> /*01*/ if ( *once != INIT_DONE ) {
> /*02*/ check( pthread_mutex_lock(&mu) == 0 );
> /*03*/ if ( *once == START_VALUE ) {
> /*04*/ *once = BEING_INITIALIZED;
> /*05*/ check( pthread_mutex_unlock(&mu) == 0 );
> /*06*/ (*func)();
> /*07*/ check( pthread_mutex_lock(&mu) == 0 );
> /*08*/ *once = INIT_DONE;
> /*09*/ check( pthread_cond_broadcast(&cv) == 0 );
> /*10*/ } else {
> /*11*/ while ( *once != INIT_DONE ) {
> /*12*/ check( pthread_cond_wait(&cv, &mu) == 0 );
> /*13*/ }
> /*14*/ }
> /*15*/ check (pthread_mutex_unlock(&mu) == 0);
> /*16*/ }
> }
>
> Wszystkie zapisy i odczyty (poza linią 01) są chronione muteksem. Tak więc:
> A) w lini 01 może zostać albo odczytana wartość początkowa, wartość z
> linii 04 lub 08
> - w przypadku odczytu INIT_DONE pomijamy cały blok - inicjalizacja
> została już wykonana
Tak, ale nie miała miejsce synchronizacja.
> - w przypadku odczytu innej wartości rozpoczynamy blok synchronizowany B
>
> B) w linii 03 może zostać albo odczytana wartość początkowa, wartość z
> linii 04 lub 08
> - w przypadku wartości innej niż START_VALUE oczekujemy w liniach 11,12
> na zakończenie inicjalizacji [*] (deadlock przy wywołaniu rekurencyjnym)
> - w przypadku wartości START_VALUE zmieniamy ją na BEING_INITIALIZED i
> kończymy blok synchronizowany - od tego momentu żaden wątek w 01 ani 03
> nie odczyta wartości START_VALUE
> - Po zakończeniu inicjalizacji zapisujemy *once = INIT_DONE i wybudzamy
> wątki czekające w linii 12 - od tego momentu nie zostanie odczytana inna
> wartość niż INIT_DONE
>
> Czekające wątki po kolei kończą oczekiwanie 12->11->15.
>
> [*] Jeżeli wartość zmieniła się na INIT_DONE po odczycie w linii 01 ale
> przed otrzymaniem muteksu to nie czekamy w linii 12 tylko kończymy na 15.
>
> Pisane na szybko więc co przeoczyłem?
Model pamięci C++11?
>> Ja potrafię to drugie.
>>
> Poproszę.
Model Pamięci ma taką cechę że zapis w wątku A jest widoczny w wątku B
gdy nastąpi uszeregowanie poprzez release w A i acquire w B. Lock() to
aquire, unlock() to release, albo można w ogóle każdą operację na
mutexie traktować 'stricter' jako sequence point - czyli jeżeli oba
wątki przejdą op na mutex to zapis w A może być odczytany w B. Jeżeli
nie ma przejścia przez mutex obu wątków mamy race, czyli wątek B
czyta potencjalnie śmieci. Zapis dotyczy zmiennych użytych tutaj i wszystkich
zapisów w func(), które po przejściu algorytmu muszą być widoczne.
func to głównie konstruktory, przejście całego algorytmu oznacza,
że obiekty są już zainicjalizowane (przez wywołanie func).
Uff, definicje z głowy ;). Wątek A i wątek B i numery linii,
możliwa sekwencja:
A linie 1 do 5 (w 2 i 5 jest mutex)
A 6: konstruktor (po to jest ten algorytm) może zapisać pola
A 7: mutex (acquire)
A 8: once = INIT_DONE
B 1: (once == INIT_DONE) == true (co nie musi być prawdą, ale może)
B 17: wątek używa wartości z A 6, które nie muszą być poprawne,
bo wątek B nie przeszedł przez żaden mutex. Może odczytać
śmieci, czyli mamy race
Powyższa sekwencja może jest mało prawdopodobna, ale mamy
data race.
Na Intelach jeżeli dobrze kojarzę to się nie ma prawa zdarzyć,
bo Intel ma taki model pamięci że jeżeli zapis do once jest widoczny
to poprzednie zapisy z func też, były wcześniej. Pisząc asma x86 można
na tym polegać, ale w bibliotece taki algorytm w C na innej platformie
nagle ma niewidoczne efekty konstruktorów. Przynajmniej wg. modelu
pamięci C11 i C++11.
W oryginalnym algorytmie zawsze będzie odpowiedni 'ordering' przez
synchronizację, bo ta zmienna thread-local jest zmieniana tylko
przy zankniętym mutex, więc pierwszy if bez przejścia przez mutex
nigdy nie będzie false. Dlatego ten algorytm jest genialny, kolejne
przejścia są bez synchronizacji.
Pozdrawiam
--
Edek
Następne wpisy z tego wątku
- 02.07.13 21:18 Michoo
- 02.07.13 23:06 Edek
- 03.07.13 02:29 Michoo
- 03.07.13 04:08 Edek
- 09.07.13 14:42 firr
- 10.07.13 15:41 firr
Najnowsze wątki z tej grupy
- Arch. Prog. Nieuprzywilejowanych w pełnej wer. na nowej s. WWW energokod.pl
- 7. Raport Totaliztyczny: Sprawa Qt Group wer. 424
- TCL - problem z escape ostatniego \ w nawiasach {}
- Nauka i Praca Programisty C++ w III Rzeczy (pospolitej)
- testy-wyd-sort - Podsumowanie
- Tworzenie Programów Nieuprzywilejowanych Opartych Na Wtyczkach
- Do czego nadaje się QDockWidget z bibl. Qt?
- Bibl. Qt jest sztucznie ograniczona - jest nieprzydatna do celów komercyjnych
- Co sciaga kretynow
- AEiC 2024 - Ada-Europe conference - Deadlines Approaching
- Jakie są dobre zasady programowania programów opartych na wtyczkach?
- sprawdzanie słów kluczowych dot. zła
- Re: W czym sie teraz pisze programy??
- Re: (PDF) Surgical Pathology of Non-neoplastic Gastrointestinal Diseases by Lizhi Zhang
- CfC 28th Ada-Europe Int. Conf. Reliable Software Technologies
Najnowsze wątki
- 2024-12-25 Wrocław => Architekt rozwiązań (doświadczenie w obszarze Java, AWS
- 2024-12-25 Warszawa => Sales Assistant <=
- 2024-12-25 Kraków => Inżynier bezpieczeństwa aplikacji <=
- 2024-12-25 Lublin => System Architect (Java background) <=
- 2024-12-25 Szczecin => Specjalista ds. public relations <=
- 2024-12-25 Wrocław => Key Account Manager <=
- 2024-12-25 Kraków => Full Stack .Net Engineer <=
- 2024-12-25 Kraków => Programista Full Stack .Net <=
- 2024-12-25 Bieruń => Regionalny Kierownik Sprzedaży (OZE) <=
- 2024-12-25 Białystok => Inżynier Serwisu Sprzętu Medycznego <=
- 2024-12-25 Białystok => Delphi Programmer <=
- 2024-12-25 Chrzanów => Team Lead / Tribe Lead FrontEnd <=
- 2024-12-25 Kraków => Ekspert IT (obszar systemów sieciowych) <=
- 2024-12-25 Mińsk Mazowiecki => Spedytor Międzynarodowy <=
- 2024-12-24 Dzisiaj Bentlejem czyli przybieżeli sześciu Króli do Rysia na kasie