Я пытаюсь понять параллелизм и лучше использовать блокировки, но этот глупый пример, который я сделал, отбрасывает меня:
int i = 0;
void foo() {
int n = i;
i = i + 1;
printf("foo: %d\n", n);
}
void boo() {
int n = i;
i = i + 1;
printf("boo: %d\n", n);
}
int main(int argc, char* argv[]) {
pthread_t p1, p2;
pthread_create(&p1, NULL, (void*) foo, NULL);
pthread_create(&p2, NULL, (void*) boo, NULL);
// wait for threads to finish
pthread_join(p1, NULL);
pthread_join(p2, NULL);
// final print
printf("main: %d\n", i);
return 0;
}
Если я правильно понимаю, i = i + 1;
в обоих foo()
и bar()
может вызвать неожиданное поведение. Одним неожиданным поведением является то, что мы получим и «foo: 0», и «bar: 0», поскольку вполне возможно, что переключение контекста произошло прямо перед i = i + 1;
, и поэтому n
всегда равно 0. Я думаю, что ожидаемое поведение что "foo: 0" "bar: 1" или "bar: 0" "foo: 1" (пожалуйста, исправьте меня, если я ошибаюсь).
Чтобы исправить это, я добавил блокировки:
int i = 0;
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
void foo() {
int n = i;
i = i + 1;
printf("foo: %d\n", n);
}
void boo() {
int n = i;
i = i + 1;
printf("boo: %d\n", n);
}
int main(int argc, char* argv[]) {
pthread_t p1, p2;
printf("Locking foo\n");
pthread_mutex_lock(&lock);
printf("Locked foo\n");
pthread_create(&p1, NULL, (void*) foo, NULL);
pthread_mutex_unlock(&lock);
printf("Unlocked foo\n");
printf("Locking boo\n");
pthread_mutex_lock(&lock);
printf("Locked boo\n");
pthread_create(&p2, NULL, (void*) boo, NULL);
pthread_mutex_unlock(&lock);
printf("Unlocked boo\n");
// wait for threads to finish
pthread_join(p1, NULL);
pthread_join(p2, NULL);
// final print
printf("main: %d\n", i);
return 0;
}
Я думаю, что это исправит неожиданные результаты, но я получил неожиданный вывод, когда запустил следующее:
Locking foo
Locked foo
Unlocked foo
Locking boo
Locked boo
foo: 0
Unlocked boo
boo: 1
main: 2
Похоже, что программа заблокировала первый поток, который вызывает foo () и затем немедленно разблокировал его, не выполняя printf? Затем происходит блокировка потока, который вызывает boo () и делает странные вещи не по порядку. Может кто-нибудь объяснить это поведение? Я бы подумал, что результат будет выглядеть так:
Locking foo
Locked foo
foo: 0
Unlocked foo
Locking boo
Locked boo
boo: 1
Unlocked boo
main: 2