Linux System Programming · intermediate · ~10 min
Pass per-thread data into `pthread_create` safely — without sharing a single loop variable across threads.
A thread function always has this signature:
void *fn(void *arg);
It receives exactly one pointer. To send more than one value, pack the values into a struct and pass the struct's address.
The classic mistake is passing the address of a loop variable (the counter i):
/* WRONG — every thread reads the same `i` */
for (int i = 0; i < N; i++)
pthread_create(&tids[i], NULL, worker, &i);
Here is the problem. The new threads do not run instantly. By the time they actually read i, the loop has usually finished and i == N. So every thread reads N, not the value you intended.
int into intptr_t, then into void *, and reverse the cast inside the thread. (intptr_t is an integer type guaranteed to be wide enough to hold a pointer.) No shared variable, no race.malloc'd struct so nothing is shared or reassigned.#include <pthread.h>
#include <stdio.h>
#include <stdint.h>
static void *worker(void *arg) {
int my_id = (int)(intptr_t)arg;
printf("thread %d alive\n", my_id);
return NULL;
}
int main(void) {
pthread_t tids[4];
for (int i = 0; i < 4; i++) {
/* cast int -> intptr_t -> void* keeps the value, not an address */
pthread_create(&tids[i], NULL, worker, (void *)(intptr_t)i);
}
for (int i = 0; i < 4; i++) pthread_join(tids[i], NULL);
return 0;
}
&i from a loop. All threads see the post-loop value of i, not their intended index.malloc'd arguments, or pass the value by value.void * argument; pack multiple values into a struct.int by value via intptr_t, or give each thread its own heap-allocated struct.