мы можем определить переменную перед вызовом функции pthread-create () - PullRequest
1 голос
/ 12 мая 2019

Я пытаюсь протестировать многопоточность на языке c и на ОС Manjaro.Я пишу небольшой код, но столкнулся со странной проблемой

Я выполняю ниже простой код, но я не получил ожидаемый результат:

#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <semaphore.h>
#define THREADS 4

void *routine1(void * x)
{
    int result =2;
    pthread_exit((void *)result);
}

int main ()
{
    int sum=0;
    int retval=0;
   pthread_t threads[THREADS];
    for ( int i=0;i<THREADS;i++)
        pthread_create(&threads[i], NULL, routine1, (void *)i );
   for (int i=0; i<THREADS; i++)
   {
     pthread_join(threads[i],&retval);
     sum+=retval;
   }
   printf("%d\n",sum);
   return 0;

}

результаткод выше:

2

но я ожидал увидеть значение 8 на выходе.после нескольких часов отладки я обнаружил, что если я объявлю переменную суммы после функции pthread_create (), код будет работать нормально:

#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <semaphore.h>
#define THREADS 4

void *routine1(void * x)
{
    int result =2;
    pthread_exit((void *)result);
}

int main ()
{
    int retval=0;
   pthread_t threads[THREADS];
   for ( int i=0;i<THREADS;i++)
   pthread_create(&threads[i], NULL, routine1, (void *)i );
   int sum=0;
   for (int i=0; i<THREADS; i++)
   {
        pthread_join(threads[i],&retval);
        sum+=retval;
   }
   printf("%d\n",sum);
   return 0;
}

, вывод кода:

 8

Какой правильный ответ.

Я хочу знать, почему первый код неправильный?это из-за функции pthread_create ()?

ПРИМЕЧАНИЕ: если вы запускаете этот код, не заботятся о предупреждениях, они все о приведении

1 Ответ

4 голосов
/ 12 мая 2019

Нет, это не заказ.Это тип из retval.Когда, передавая &retval в pthread_join, это неправильный тип / sizeof.

Когда retval является int, это только 4 байта, но [при условии 64-битной компиляции], pthread_joinожидает указатель на void *, что составляет 8 байтов.

Это вызывает неопределенное поведение, потому что вызов записывает 8 байтов в переменную, которая составляет всего 4 байта.Оставшиеся 4 байта превышают размер retval и могут перезаписывать что угодно в стеке.

В вашем втором примере было то же неопределенное поведение, но нам просто «повезло»и получил ожидаемый результат [вероятно, потому что порядок переменных в кадре стека изменился, чтобы избежать выдачи UB неожиданного результата].Но у обоих все еще было UB.

Кроме того, при приведении к / от указателя мы должны использовать long вместо int [для предотвращения предупреждений компилятора].

Вот исправленноекод:

#include <stdio.h>
#include <string.h>
#include <pthread.h>
#include <semaphore.h>
#define THREADS 4

void *
routine1(void *x)
{
#if 0
    int result = 2;
#else
    long result = 2;
#endif

    pthread_exit((void *) result);
}

int
main()
{
    int sum = 0;
#if 0
    int retval = 0;
#else
    void *retval;
#endif
    pthread_t threads[THREADS];

#if 0
    for (int i = 0; i < THREADS; i++)
        pthread_create(&threads[i], NULL, routine1, (void *) i);
#else
    for (long i = 0; i < THREADS; i++)
        pthread_create(&threads[i], NULL, routine1, (void *) i);
#endif

    for (int i = 0; i < THREADS; i++) {
        pthread_join(threads[i], &retval);
#if 0
        sum += retval;
#else
        sum += (long) retval;
#endif
    }

    printf("%d\n", sum);

    return 0;

}
...