Несколько аргументов функции, вызываемой pthread_create ()?

96

Мне нужно передать несколько аргументов функции, которую я хотел бы вызвать в отдельном потоке. Я читал, что типичный способ сделать это - определить структуру, передать функции указатель на нее и разыменовать ее для аргументов. Однако я не могу заставить это работать:

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

struct arg_struct {
    int arg1;
    int arg2;
};

void *print_the_arguments(void *arguments)
{
    struct arg_struct *args = (struct arg_struct *)args;
    printf("%d\n", args -> arg1);
    printf("%d\n", args -> arg2);
    pthread_exit(NULL);
    return NULL;
}

int main()
{
    pthread_t some_thread;
    struct arg_struct args;
    args.arg1 = 5;
    args.arg2 = 7;

    if (pthread_create(&some_thread, NULL, &print_the_arguments, (void *)&args) != 0) {
        printf("Uh-oh!\n");
        return -1;
    }

    return pthread_join(some_thread, NULL); /* Wait until thread is finished */
}

Результат для этого должен быть:

5
7

Но когда я запускаю его, я получаю:

141921115
-1947974263

Кто-нибудь знает, что я делаю не так?

Майкл
источник
2
попробовать разместить его в куче?
Carson Myers
1
@Carson Почему это должно иметь значение?
sigjuice
5
Ваша структура должна жить как минимум столько же, сколько и ваш поток. Если вы создаете поток и возвращаетесь из функции, вызвавшей pthread_create (), структура, выделенная в стеке, может быть перезаписана другими данными и может вызвать проблемы в вашей функции потока. В этом примере это не проблема, поскольку создающий поток ожидает завершения рабочего потока перед возвратом.
Commodore Jaeger
@ Коммодор Джагер Ой! Спасибо, это проблема, с которой я столкнулся с другим человеком, с которым я работал. Я исправил это, разместив его в куче с помощью malloc (), как сказал Карсон. Теперь это имеет гораздо больший смысл.
Майкл

Ответы:

78

Потому что ты сказал

struct arg_struct *args = (struct arg_struct *)args;

вместо того

struct arg_struct *args = arguments;

sigjuice
источник
5
@sigjuice, у меня не работает. Я вижу ошибку компиляции: недопустимое преобразование из void * в arg_struct *.
Нешта
20

использовать

struct arg_struct *args = (struct arg_struct *)arguments;

на месте

struct arg_struct *args = (struct arg_struct *)args;
Акаш Агравал
источник
4

main()имеет собственные переменные потока и стека. либо выделите память для аргументов в куче, либо сделайте ее глобальной:

struct arg_struct {
    int arg1;
    int arg2;
}args;

//declares args as global out of main()

Затем, конечно, измените ссылки с args->arg1на и args.arg1т. Д.

Пламен Панов
источник
2

Использование:

struct arg_struct *args = malloc(sizeof(struct arg_struct));

И передайте эти аргументы следующим образом:

pthread_create(&tr, NULL, print_the_arguments, (void *)args);

Не забывайте бесплатные аргументы! ;)

Эльхам
источник
1

Аргументы print_the_arguments - это аргументы, поэтому вы должны использовать:

struct arg_struct *args = (struct arg_struct *)arguments. 
Камень. Картонная коробка
источник
1
struct arg_struct *args = (struct arg_struct *)args;

-> это назначение неверно, я имею в виду, что в этом контексте следует использовать аргумент переменной. Ура !!!

Джашмикант
источник
1

При создании потока этого кода передается адрес указателя функции. Оригинал pthread_create(&some_thread, NULL, &print_the_arguments, (void *)&args) != 0

Его следует читать как pthread_create(&some_thread, NULL, print_the_arguments, (void *) &args)

Хороший способ запомнить - все аргументы этой функции должны быть адресами.

some_threadобъявляется статически, поэтому адрес отправляется правильно с использованием &.

Я бы создал pthread_attr_tпеременную, затем использовал бы pthread_attr_init()ее и передал адрес этой переменной. Но передача NULLуказателя также допустима.

То, &что вызывает проблему, - это перед меткой функции. Используемая метка уже является void*функцией, поэтому необходима только метка.

Сказать != 0последний аргумент, по-видимому, приведет к неопределенному поведению. Добавление этого означает, что вместо ссылки передается логическое значение.

Ответ Акаша Агравала также является частью решения проблемы этого кода.

Райшаун Престон
источник
1

У меня тот же вопрос, что и у оригинального постера, Майкл.

Однако я безуспешно пытался применить ответы, представленные для исходного кода.

После некоторых проб и ошибок вот моя версия кода, которая работает (или, по крайней мере, работает для меня!). И если вы присмотритесь, вы заметите, что это отличается от ранее опубликованных решений.

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

struct arg_struct
{
   int arg1;
   int arg2;
} *args;

void *print_the_arguments(void *arguments)
{
   struct arg_struct *args = arguments;
   printf("Thread\n");
   printf("%d\n", args->arg1);
   printf("%d\n", args->arg2);
   pthread_exit(NULL);
   return NULL;
}

int main()
{
   pthread_t some_thread;
   args = malloc(sizeof(struct arg_struct) * 1);

   args->arg1 = 5;
   args->arg2 = 7;

   printf("Before\n");
   printf("%d\n", args->arg1);
   printf("%d\n", args->arg2);
   printf("\n");


   if (pthread_create(&some_thread, NULL, &print_the_arguments, args) != 0)
   {
      printf("Uh-oh!\n");
      return -1;
   }

   return pthread_join(some_thread, NULL); /* Wait until thread is finished */
}
VeeDub
источник