pthreads
Stan wyścigu w wątkach
Szukaj…
Wprowadzenie
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.