Szukaj…


Wprowadzenie

Podczas pisania aplikacji wielowątkowych jednym z najczęstszych problemów są warunki wyścigowe. Więc dokumentujemy, jak je wykrywasz? i jak sobie z nimi radzisz?

Przykład: Rozważmy dwa wątki T1 i T2.

Jak je wykrywasz?

Jeśli ta sama lokalizacja zmiennej / zasobu / pamięci jest dostępna dla wielu wątków, a przynajmniej ten wątek zmienia wartość lokalizacji zmiennej / zasobu / pamięci , może wystąpić warunek wyścigu . Ponieważ jeśli wątek zmienia wartość położenia zmiennej / zasobu / pamięci, a inny wątek próbuje odczytać to samo, wówczas nie otrzyma zaktualizowanej wartości.

Uwaga : jeśli wszystkie wątki tylko odczytują lokalizację zmiennej / zasobu / pamięci, wówczas Warunek Wyścigu nie wystąpi.

Przykład: Program cierpi na stan wyścigu

#include <stdio.h>
#include <pthread.h>

int x= 0;

void* fun(void* in)
{
    int i;
    for ( i = 0; i < 10000000; i++ )
    {
        x++;
    }
}

int main()
{
    pthread_t t1, t2;
    printf("Point 1 >> X is: %d\n", x);

    pthread_create(&t1, NULL, fun, NULL);
    pthread_create(&t2, NULL, fun, NULL);
    pthread_join(t1, NULL);
    pthread_join(t2, NULL);

    printf("Point 2 >> X is: %d\n", x);
    return 0;
}

Dane wyjściowe na moim ekranie to:

Point 1 >> X is: 0
Point 2 >> X is: 9925047

Twoja wydajność będzie się różnić. Ale na pewno nie będzie to 20 000 000. Ponieważ oba wątki wykonują tę samą pętlę i mają zmienną globalną int x;

for ( i = 0; i < 10000000; i++ )
{
   x++; 
}

Zatem końcowa wartość x w linii Point 2 >> X is: 9925047 powinna wynosić 20 000 000. Ale tak nie jest.

Stan x może być zmieniony przez inny wątek podczas odczytywania x i gdy jest on ponownie zapisywany.

Powiedzmy, że wątek pobiera wartość x, ale jeszcze jej nie zapisał. Inny wątek może również pobrać tę samą wartość x (ponieważ żaden wątek go jeszcze nie zmienił), a następnie oba zapisywałyby tę samą wartość (x + 1) z powrotem w x!

Przykład:

Wątek 1: czyta x, wartość wynosi 7

Wątek 1: dodaj 1 do x, wartość wynosi teraz 8

Wątek 2: czyta x, wartość wynosi 7

Wątek 1: przechowuje 8 na x

Wątek 2: dodaje 1 do x, wartość wynosi teraz 8

Wątek 2: przechowuje 8 na x

Jak sobie z nimi radzisz?

Można uniknąć warunków wyścigu poprzez zastosowanie pewnego rodzaju mechanizmu blokującego przed kodem, który uzyskuje dostęp do udostępnionego zasobu lub wzajemnego wykluczenia.

Zmodyfikowany program:

Przykład: problem z warunkami wyścigu rozwiązany

#include <stdio.h>
#include <pthread.h>

int x= 0;
//Create mutex
pthread_mutex_t test_mutex;

void* fun(void* in)
{
    int i;
    for ( i = 0; i < 10000000; i++ )
    {
        //Lock mutex before going to change variable
        pthread_mutex_lock(&test_mutex);
        x++;
        //Unlock mutex after changing the variable
        pthread_mutex_unlock(&test_mutex);
    }
}

int main()
{
    pthread_t t1, t2;
    printf("Point 1 >> X is: %d\n", x);

    //Initlize mutex
    pthread_mutex_init(&test_mutex, NULL);

    pthread_create(&t1, NULL, fun, NULL);
    pthread_create(&t2, NULL, fun, NULL);
    pthread_join(t1, NULL);
    pthread_join(t2, NULL);

    //Destroy mutex after use
    pthread_mutex_destroy(&test_mutex);
    printf("Point 2 >> X is: %d\n", x);
    return 0;
}

Oto wynik:

Point 1 >> X is: 0
Point 2 >> X is: 20000000

Tutaj odpowiedź pojawia się za 20 000 000 za każdym razem.

Uwaga : Zmodyfikowany program, wolny od błędów warunków wyścigu, będzie wymagał dużo pracy. Ponieważ blokada i odblokowanie mutex jest przeciążone.



Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow