Pthreads и не разделяемые переменные - PullRequest
0 голосов
/ 04 июня 2018

Следуя этому руководству: https://www.pluralsight.com/courses/linux-network-programming Я обнаружил очень интересное поведение, пожалуйста, проверьте следующий код:

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

void *func(void *arg)
{
    pthread_exit((void *)99);
}

int main()
{    
    pthread_t handle;
    int exitcode;
    int i = 0;
    int y = 5;
    while (1) {
        y++;
        // i++;
        printf("primary thread: y == %d\n", y);
        pthread_create(&handle, NULL, func, "hi!");
        pthread_join(handle, (void **)&exitcode);
        sleep(1);
    }    
}

//gcc -o t failtesting.c -O0  -l pthread  ; ./t
//primary thread: y == 6
//primary thread: y == 1
//primary thread: y == 1
//^C

каким-то образом присоединение дочернего потока сбрасывает переменную y в 0, почему это происходит?

Самое странное: если вы раскомментируете i ++, все возвращается на круги своя:

gcc -o t failtesting.c -O0  -l pthread  ; ./t 
primary thread: y == 5
primary thread: y == 6
primary thread: y == 7
primary thread: y == 8

1 Ответ

0 голосов
/ 04 июня 2018

This ...

    int exitcode;

[...]

        pthread_join(handle, (void **)&exitcode);

... производит неопределенное поведение, потому что ссылка &exitcode являетсяint, но pthread_join приведет к тому, что значение будет записано в него, как если бы оно было void *.

. Этого вполне достаточно, чтобы поведение было неопределенным, независимо от других соображений.,Однако, размышляя о , почему C может объявлять такие ситуации как UB, учтите, что довольно часто размер void * больше, чем размер int, так чтодолжно произойти, когда программа пытается записать данные в пространство, слишком маленькое для этого?

Самое странное: если вы раскомментируете i ++, все возвращается к нормальной жизни

Такие аномалии являются явным признаком того, что ваша программа демонстрирует UB.Стандарт C прямо отрицает наличие какого-либо объяснения этому - это часть того, что означает «неопределенное поведение».

В любом случае, похоже, что вы этого хотите, вместо этого:

    void *exit_ptr;
    pthread_join(handle, &exit_ptr);
    exitcode = (int) exit_ptr;

Будьте готовы к тому, что компилятор выдаст вполне обоснованное предупреждение о приведении указателя к int, хотя вы должны иметь возможность заставить его замолчать, приведя вместо него intptr_t.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...