Vários argumentos para a função chamada por pthread_create ()?

93

Preciso passar vários argumentos para uma função que gostaria de chamar em um segmento separado. Eu li que a maneira típica de fazer isso é definir uma estrutura, passar um ponteiro para a função e desreferenciá-la para os argumentos. No entanto, não consigo fazer isso funcionar:

#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 */
}

A saída para isso deve ser:

5
7

Mas quando eu o executo, eu realmente obtenho:

141921115
-1947974263

Alguém sabe o que estou fazendo de errado?

Michael
fonte
2
tente alocá-lo na pilha?
Carson Myers
1
@Carson Por que isso faria diferença?
sigjuice
5
Sua estrutura deve durar pelo menos tanto tempo quanto seu segmento. Se você estiver criando uma thread e retornando da função que chamou pthread_create (), a estrutura alocada na pilha pode ser substituída por outros dados e pode causar problemas em sua função de thread. Neste exemplo, isso não é um problema, já que o thread de criação espera que o thread de trabalho seja concluído antes de retornar.
Comodoro Jaeger
@Commodore Jaeger Oh! Obrigado, esse é o problema que eu estava tendo com o outro com quem estava trabalhando. Corrigi-o alocando-o no heap usando malloc (), como disse Carson. Isso faz muito mais sentido agora.
Michael

Respostas:

77

Porque voce diz

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

ao invés de

struct arg_struct *args = arguments;

Sigjuice
fonte
4
@sigjuice, não funciona para mim. Eu vejo um erro de compilação: conversão inválida de 'void *' para 'arg_struct *'.
Neshta de
20

usar

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

no lugar de

struct arg_struct *args = (struct arg_struct *)args;
Akash Agrawal
fonte
4

main()tem suas próprias variáveis ​​de thread e pilha. aloque memória para 'args' no heap ou torne-o global:

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

//declares args as global out of main()

Então, é claro, altere as referências de args->arg1para args.arg1etc.

Plamen Panov
fonte
2

Usar:

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

E passe esses argumentos assim:

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

Não se esqueça de args grátis! ;)

Elham
fonte
1

Os argumentos de print_the_arguments são argumentos, então você deve usar:

struct arg_struct *args = (struct arg_struct *)arguments. 
Stone.Carton
fonte
1
struct arg_struct *args = (struct arg_struct *)args;

-> esta atribuição está errada, quero dizer que o argumento variável deve ser usado neste contexto. Felicidades!!!

Jashmikant
fonte
1

Na criação de thread desse código, o endereço de um ponteiro de função está sendo passado. O original pthread_create(&some_thread, NULL, &print_the_arguments, (void *)&args) != 0

Deve ser lido como pthread_create(&some_thread, NULL, print_the_arguments, (void *) &args)

Uma boa maneira de lembrar é que todos os argumentos dessa função devem ser endereços.

some_threadé declarado estaticamente, então o endereço é enviado corretamente usando &.

Eu criaria uma pthread_attr_tvariável, usaria pthread_attr_init()nela e passaria o endereço dessa variável. Mas, passar um NULLponteiro também é válido.

O &na frente do rótulo da função é o que está causando o problema aqui. O rótulo usado já é umvoid* para uma função, portanto, apenas o rótulo é necessário.

Dizer != 0com o argumento final pareceria causar um comportamento indeterminado. Adicionar isso significa que um booleano está sendo passado em vez de uma referência.

A resposta de Akash Agrawal também é parte da solução para o problema desse código.

Rayshaun Preston
fonte
1

Tenho a mesma pergunta do autor do pôster original, Michael.

No entanto, tentei aplicar as respostas enviadas para o código original sem sucesso

Depois de algumas tentativas e erros, aqui está minha versão do código que funciona (ou pelo menos funciona para mim!). E se você olhar com atenção, notará que é diferente das soluções postadas anteriormente.

#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
fonte