Linux System Programming · intermediate · ~10 min

Passing arguments to threads

Pass per-thread data into pthread_create — without sharing a loop variable.

Lesson

A thread function has signature void *fn(void *arg). You pass exactly one pointer. To send multiple values, pack them into a struct and pass its address.

Critical bug pattern: passing the address of a loop variable.

/* WRONG — every thread reads the same `i` */
for (int i = 0; i < N; i++)
    pthread_create(&tids[i], NULL, worker, &i);

By the time the threads run, the loop has finished and i == N. All threads read N. The fix: pass by value (cast int to/from intptr_t), or allocate a per-thread struct on the heap.

Code examples

#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;
}

Common mistakes

  • Passing &i from a loop. All threads see the post-loop value of i.
  • Stack-allocating an args struct and letting the function return before the thread reads it. Use malloc'd args or pass by value.

Summary

Pass one pointer; pack multiple values in a struct. Never pass the address of a stack-local loop variable — the loop will reassign it before the thread reads.

Practice with these exercises