Gradient
Gradient

Reputation: 2343

pthread_create and passing an integer as the last argument

I have the following functions :

void *foo(void *i) {
    int a = (int) i;
}

int main() {
    pthread_t thread;
    int i;
    pthread_create(&thread, 0, foo, (void *) i);
}

At compilation, there are some errors about casting ((void *) i and int a = (int) i). How can I pass an integer as the last argument of pthread_create properly?

Upvotes: 48

Views: 115938

Answers (6)

Hackaholic
Hackaholic

Reputation: 19733

you can intprt_t
Using intptr_t is useful when you need to convert between pointers and integers without loss of information or when you want to ensure that a pointer can be safely converted to an integer type. It's commonly used in scenarios where you need to store a pointer in an integer variable or pass a pointer as an integer argument to a function.

void *foo(void *i) {
    int a = (intptr_t)i;
}

int main() {
    pthread_t thread;
    int i;
    pthread_create(&thread, 0, foo, (void *)(intptr_t)i);  // cast i to intptr_t type
}

Upvotes: 0

Schmurfy
Schmurfy

Reputation: 1725

While this is an old question there is one option missing when all you need is to pass a positive integer like a descriptor: you can pass it directly as the address, while it it a hack it works well and avoid allocating anything :)

NOTE: the size of the integer must match the size of a pointer on your OS but nowadays most systems are native 64bits.

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

void *_thread_loop(void *p)
{
  uint64_t n = (uint64_t)p;

  printf("received %llu\n", n);

  return NULL;
}



int main(int argc, char const *argv[])
{
  pthread_t read_thread_id;
  uint64_t n = 42;
  pthread_create(&read_thread_id, NULL, _thread_loop, (void *)n);

  pthread_join(read_thread_id, NULL);
  return 0;
}

Upvotes: 4

Jerska
Jerska

Reputation: 12002

Old question, but I faced the same problem today, and I decided not to follow this path. My application was really about performance, so I chose to have this array of ints declared statically.

Since I don't know a lot of applications where your pthread_join / pthread_cancel is in another scope than your pthread_create, I chose this way :

#define NB_THREADS 4

void *job(void *_i) {
  unsigned int i = *((unsigned int *) _i);
}

int main () {
  unsigned int ints[NB_THREADS];
  pthread_t    threads[NB_THREADS];
  for (unsigned int i = 0; i < NB_THREADS; ++i) {
    ints[i] = i;
    pthread_create(&threads[i], NULL, job, &ints[i]);
  }
}

I find it more elegant, more efficient, and you don't have to worry about freeing since it only lives in this scope.

Upvotes: 8

Crowman
Crowman

Reputation: 25908

Building on szx's answer (so give him the credit), here's how it would work in your for loop:

void *foo(void *i) {
    int a = *((int *) i);
    free(i);
}

int main() {
    pthread_t thread;
    for ( int i = 0; i < 10; ++1 ) {
        int *arg = malloc(sizeof(*arg));
        if ( arg == NULL ) {
            fprintf(stderr, "Couldn't allocate memory for thread arg.\n");
            exit(EXIT_FAILURE);
        }

        *arg = i;
        pthread_create(&thread, 0, foo, arg);
    }

    /*  Wait for threads, etc  */

    return 0;
}

On each iteration of the loop, you're allocating new memory, each with a different address, so the thing that gets passed to pthread_create() on each iteration is different, so none of your threads ends up trying to access the same memory and you don't get any thread safety issues in the way that you would if you just passed the address of i. In this case, you could also set up an array and pass the addresses of the elements.

Upvotes: 56

P.P
P.P

Reputation: 121357

You should cast the address of i (rather than the value of i as you do now) in the last argument of pthread_create().

pthread_create(&thread, 0, foo, (void *) &i);
                                         ^  is missing

And the casting is wrong in your function too. It should be:

int a = *((int*) i);
  1. If you intend to read the value, you should also initialize i to some value in main() as it's uninitialized now.

2 Use proper definition for main():

 int main(void) 

or int main(int argc, char *argv[]) or its equivalent.

Upvotes: 11

szx
szx

Reputation: 6926

You can allocate an int on the heap and pass it to pthread_create(). You can then deallocate it in your thread function:

void *foo(void *i) {
    int a = *((int *) i);
    free(i);
}

int main() {
    pthread_t thread;
    int *i = malloc(sizeof(*i));
    pthread_create(&thread, 0, foo, (void *) i);
}

Upvotes: 27

Related Questions