https://godbolt.org/z/sYKoKvo9r
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
void* thread_body_1(void* arg) {
int* shared_var_ptr = (int*)arg;
(*shared_var_ptr)++;
printf("%d", *shared_var_ptr);
return NULL;
}
void* thread_body_2(void* arg) {
int* shared_var_ptr = (int*)arg;
*shared_var_ptr += 2;
printf("%d", *shared_var_ptr);
return NULL;
}
int main(void) {
int shared_var = 0;
pthread_t thread1;
pthread_t thread2;
printf("----------------------- %s \t\t\t%d\n", __FUNCTION__, shared_var);
int result1 = pthread_create(&thread1, NULL,
thread_body_1, &shared_var);
int result2 = pthread_create(&thread2, NULL,
thread_body_2, &shared_var);
if (result1 || result2) {
fprintf(stderr, " pthread_create: result1 = %d || result2 = %d\n", result1, result2);
exit(1);
}
result1 = pthread_join(thread1, NULL);
result2 = pthread_join(thread2, NULL);
if (result1 || result2) {
fprintf(stderr, "pthread_join: result1 = %d || result2 = %d\n", result1, result2);
exit(2);
}
printf("\n----------------------- %s \t\t\t%d\n", __FUNCTION__, shared_var);
return 0;
}
Rozumiem to, jak program daje wyniki:
13
23
12
21
Ale nie rozumiem tego jak program daje wyniki:
31
32
Przypuszczam, ze funkcja printf niekoniecznie odwoluje sie do wartosci aktualnej wskazywanej przez shared_var_ptr (3), tylko korzysta z jakiegos cache - albo nastapilo przelaczenie kontekstu na inny thread przed samym wyswietleniem zmiennej wskazywanej przez shared_var_ptr, kiedy wszystko bylo gotowe do wyswietlenia 1 lub 2, a po powrocie do tego threada nie wykonano sprawdzenia jaka jest wartosc zmiennej wskazywanej przez shared_var_ptr (a zmienila sie na 3), bo zrobiono to juz wczesniej. Hipotetyczna kolejnosc:
main
------------------- przelaczenie kontekstu
thread_body_1
int* shared_var_ptr = (int*)arg; // shared_var = 0
(shared_var_ptr)++; // shared_var = 1
/ przelaczenie kontekstu na inny thread przed samym wyswietleniem zmiennej wskazywanej przez shared_var_ptr, kiedy wszystko bylo gotowe do wyswietlenia 1 /
------------------- przelaczenie kontekstu
thread_body_2
int shared_var_ptr = (int*)arg; // shared_var = 1
*shared_var_ptr += 2; // shared_var = 3
printf("%d", *shared_var_ptr); // shared_var = 3
return NULL;
------------------- przelaczenie kontekstu
thread_body_1
printf("%d", shared_var_ptr); / po powrocie do tego threada nie wykonano sprawdzenia jaka jest wartosc zmiennej wskazywanej przez shared_var_ptr (a zmienila sie na 3), bo zrobiono to juz wczesniej i wskutek tego teraz wyswietlono 1 */
Zdaje sobie sprawe, ze podana powyzej kolejnosc jest uproszczona bo przelaczenie kontekstu odbywa sie na poziomie instrukcji asemblera, a nawet instrukcja int* shared_var_ptr = (int*)arg; jest w asemblerze zlozona z wielu instrucji, a nie jednej jak w C