Volumetricsteve
Volumetricsteve

Reputation: 213

In C, how do I pass variables to functions in Pthreads upon thread creation?

Working from this example:

https://computing.llnl.gov/tutorials/pthreads/samples/hello.c

I've worked backwards and tried to edit in what I'm hoping to accomplish. I'd like to pass data to the thread being spawned.

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
long NUM_THREADS=0;

void *Entropy(void *depth)
{
   long tid;
   tid = (long)depth;
   printf("This is where things get done.\n", tid);
   pthread_exit(NULL);
}

int main(int argc, char *argv[])
{
   NUM_THREADS = sysconf(_SC_NPROCESSORS_ONLN);
   printf("Cores: %i\n", NUM_THREADS);
   pthread_t threads[NUM_THREADS];
   int rc;
   long t;
   int depth;
   depth = atoi(argv[1]);
   for(t=0;t<NUM_THREADS;t++){
     printf("In main: creating thread %ld\n", t);
     rc = pthread_create(&threads[t], NULL, Entropy(depth), (void *)t);
     if (rc){
       printf("ERROR; return code from pthread_create() is %d\n", rc);
       exit(-1);
       }
     }
   pthread_exit(NULL);
}

I see on line:

rc = pthread_create(&threads[t], NULL, Entropy(depth), (void *)t);

My function Entropy gets called here, so I thought I'd try to tack on some brackets and pass a variable to that function the way I'd seen it done before. This seems to be a little different though, since this whole line returns something to rc, I wonder if that changes how I pass data to my thread, but I'm not sure how else I'd do it.

Right now this code compiles and runs, int main() goes fine without a hitch but it seg faults the moment it tries to create new threads.

Upvotes: 3

Views: 1954

Answers (2)

Sergio
Sergio

Reputation: 8209

Your code crashes since you pass incorrect parameters:

rc = pthread_create(&threads[t], NULL, Entropy(depth), (void *)t);
                                    // ^^^^^^^^^^^^^^

Here you should pass function pointer void *(*)(void *) but you are passing void *, and moreover value is unspecified since Entropy() has no return statement (did you turn warnings on at all?). I guess it should be like this:

rc = pthread_create(&threads[t], NULL, Entropy, (void *)t);

Next, how to pass parameter to thread routine? Technically you can use any pointer, but you should think twice about what you are passing. First of all pointed data must be valid when new thread runs. I.e. you shouldn't pass addresses of any locals except if you are sure that thread is finished when you are leaving scope of passed data - use pthread_join(new_thread) at the scope end to achieve that. Another approach is to pass pointer to data at global scope, that is surely valid at any moment. But there is one flaw - such data are visible to all threads, so you may accidentally make a mess. To avoid it - use dynamic memory - allocate data block with malloc() pass pointer to thread and free it in that thread. Latter option reduces chances to corrupt someone's else data.

#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
long NUM_THREADS=0;

void *Entropy(void *depth)
{
   long tid = *((long *)depth);
   free(depth);
   printf("This is where things get done.\n", tid);
   return NULL;
}

int main(int argc, char *argv[])
{
   NUM_THREADS = sysconf(_SC_NPROCESSORS_ONLN);
   printf("Cores: %i\n", NUM_THREADS);
   pthread_t threads[NUM_THREADS];
   int rc;
   long t;
   int depth;
   depth = atoi(argv[1]);
   for(t=0;t<NUM_THREADS;t++){
     long *arg = malloc(sizeof(*arg));
     *arg = t;
     printf("In main: creating thread %ld\n", t);
     rc = pthread_create(&threads[t], NULL, Entropy, arg);
     if (rc){
       printf("ERROR; return code from pthread_create() is %d\n", rc);
       exit(-1);
       }
   }
   for(t=0;t<NUM_THREADS;t++){
     pthread_join(threads[t], NULL);
   }
}

Upvotes: 1

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 726579

In order to pass data to a thread you need to prepare the data in some place in memory, and pass a pointer to that place into pthread_create. It is pthread_create's job to pass that pointer to the runner function of your thread:

typedef struct {
    long tid;
    int depth;
}thread_data;
...
void *Entropy(void *dataPtr) {
   thread_data *data= (thread_data*)dataPtr;
   printf("This is where things get done for %li.\n", data->tid);
   pthread_exit(NULL);
}
...
pthread_t threads[NUM_THREADS];
thread_data data[NUM_THREADS];
...
for(t=0;t<NUM_THREADS;t++) {
    data[t].tid = t;
    data[t].depth = depth;
    rc = pthread_create(&threads[t], NULL, Entropy, (void *)&data[t]);
}

Upvotes: 4

Related Questions