131

I need to pass multiple arguments to a function that I would like to call on a separate thread. I've read that the typical way to do this is to define a struct, pass the function a pointer to that, and dereference it for the arguments. However, I am unable to get this to work:

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

The output for this should be:

5
7

But when I run it I actually get:

141921115
-1947974263

Anyone know what I'm doing wrong?

Michael
  • 4,700
  • 9
  • 35
  • 42
  • 3
    try allocating it on the heap? – Carson Myers Aug 30 '09 at 00:56
  • 1
    @Carson Why should that make a difference? – sigjuice Aug 30 '09 at 01:04
  • 7
    Your structure should live at least as long as your thread. If you're creating a thread and returning from the function that called pthread_create(), the structure allocated on the stack may get overwritten by other data and could cause problems in your thread function. In this example, that's not a problem, since the creating thread waits for the worker thread to complete before returning. – Commodore Jaeger Aug 30 '09 at 02:55
  • 1
    @Commodore Jaeger Oh! Thank you, that's the problem I was having with the other I was working with. I fixed it by allocating it on the heap using malloc(), as Carson said. That makes much more sense now. – Michael Aug 30 '09 at 11:27

9 Answers9

97

Because you say

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

instead of

struct arg_struct *args = arguments;

sigjuice
  • 28,661
  • 12
  • 68
  • 93
  • 9
    @sigjuice, It doesn't work for me. I see compilation error: invalid conversion from ‘void*’ to ‘arg_struct*’. – Neshta Oct 15 '14 at 17:17
  • 1
    @Neshta: That means you're not using a C compiler, but are probably using a C++ compiler. It that case, you should probably be using `std::thread` instead – Chris Dodd Oct 01 '22 at 02:06
27

use

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

in place of

struct arg_struct *args = (struct arg_struct *)args;
Akash Agrawal
  • 4,711
  • 5
  • 28
  • 26
6

main() has it's own thread and stack variables. either allocate memory for 'args' in the heap or make it global:

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

//declares args as global out of main()

Then of course change the references from args->arg1 to args.arg1 etc..

akjoshi
  • 15,374
  • 13
  • 103
  • 121
Plamen Panov
  • 61
  • 1
  • 1
3

Use:

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

And pass this arguments like this:

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

Don't forget free args! ;)

Unihedron
  • 10,902
  • 13
  • 62
  • 72
Elham
  • 39
  • 3
3

I have the same question as the original poster, Michael.

However I have tried to apply the answers submitted for the original code without success

After some trial and error, here is my version of the code that works (or at least works for me!). And if you look closely, you will note that it is different to the earlier solutions posted.

#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
  • 61
  • 7
2

In this code's thread creation, the address of a function pointer is being passed. The original pthread_create(&some_thread, NULL, &print_the_arguments, (void *)&args != 0)

It should read as pthread_create(&some_thread, NULL, print_the_arguments, (void *) &args)

A good way to remember is that all of this function's arguments should be addresses.

some_thread is declared statically, so the address is sent properly using &.

I would create a pthread_attr_t variable, then use pthread_attr_init() on it and pass that variable's address. But, passing a NULL pointer is valid as well.

The & in front of the function label is what is causing the issue here. The label used is already a void* to a function, so only the label is necessary.

To say != 0 with the final argument would seem to cause undetermined behavior. Adding this means that a boolean is being passed instead of a reference.

Akash Agrawal's answer is also part of the solution to this code's problem.

1

The args of print_the_arguments is arguments, so you should use:

struct arg_struct *args = (struct arg_struct *)arguments. 
Floern
  • 33,559
  • 24
  • 104
  • 119
1
struct arg_struct *args = (struct arg_struct *)args;

--> this assignment is wrong, I mean the variable argument should be used in this context. Cheers!!!

Scalway
  • 1,633
  • 10
  • 18
Jashmikant
  • 11
  • 1
0

Since asking the same question but for C++ is considered a duplicate I might as well supply C++ code as an answer.

//  hello-2args.cpp
// https://stackoverflow.com/questions/1352749
#include <iostream>
#include <omp.h>
#include <pthread.h>
using namespace std;

typedef struct thread_arguments {
  int thrnr;
  char *msg;
} thargs_t;

void *print_hello(void *thrgs) {
  cout << ((thargs_t*)thrgs)->msg << ((thargs_t*)thrgs)->thrnr << "\n";
  pthread_exit(NULL);
}

int main(int argc, char *argv[]) {
  cout << " Hello C++!\n";
  const int NR_THRDS = omp_get_max_threads();
  pthread_t threads[NR_THRDS];
  thargs_t thrgs[NR_THRDS];
  for(int t=0;t<NR_THRDS;t++) {
    thrgs[t].thrnr = t;
    thrgs[t].msg = (char*)"Hello World. - It's me! ... thread #";
    cout << "In main: creating thread " << t << "\n";
    pthread_create(&threads[t], NULL, print_hello, &thrgs[t]);
  }
  for(int t=0;t<NR_THRDS;t++) {
    pthread_join(threads[t], NULL);
  }
  cout << "After join: I am always last. Byebye!\n";
  return EXIT_SUCCESS;
}

Compile and run by using one of the following:

g++ -fopenmp -pthread hello-2args.cpp && ./a.out # Linux
g++ -fopenmp -pthread hello-2args.cpp && ./a.exe # MSYS2, Windows
Henke
  • 4,445
  • 3
  • 31
  • 44