← Interlude: Thread API
Thread creation: pthread_create § 27.1–27.2 · pp. 285-289

We’ll walk through the pthread thread-creation API. The interesting bit is how arguments get passed and what the thread function’s return value really means.

Q1 of 5

What does pthread_create() take as its argument-passing mechanism?

A single void* pointer

Correct

Right — one void * slot. To pass multiple values you bundle them in a struct and hand over a pointer to it.

Q2 of 5

Why is returning a pointer to a stack variable from a thread dangerous?

Stack memory is freed when the thread exits

Correct

Exactly. The stack unwinds at exit so any pointer into it dangles. You need heap (or a caller-owned buffer) for values that must outlive the thread.

Q3 of 5

What is the function-pointer signature pthread_create expects for the start routine?

int (*)(void *)

Wrong

Close, but the return type is wrong — start_routine is void *(*)(void *). It returns a void pointer so the thread can hand any value back to whoever calls pthread_join.

Q4 of 5

If pthread_create fails, where does it report the error?

It sets errno and returns -1

Wrong

Common mix-up with classic POSIX syscalls — pthread_create actually returns the error code directly (0 on success, e.g. EAGAIN on resource exhaustion). It does NOT touch errno.

Q5 of 5

When you need multiple arguments, what does the canonical pattern look like?

Pack them into a struct, pass &struct as the void *

Correct

Exactly. Caller allocates the struct (heap or a frame guaranteed to outlive the thread), hands its address to pthread_create, the start routine casts it back. Same pattern is what you’ll see in every pthread codebase.

Nice work — 3 of 5 correct. Re-study any time to retry the same questions.

Thread creation: pthread_create

pthread_create

  • Spawns a new thread running fn(arg). The kernel decides when the child actually starts — could be before or after the parent’s next line.
  • Signature: int pthread_create(pthread_t *t, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg);
  • attr is almost always NULL (default attributes).

Arguments: one void * slot

  • Only a single void * gets through. To pass multiple values, bundle them in a struct and hand over its address:
typedef struct { int a; double b; } myarg_t;
myarg_t args = { 10, 12.34 };
pthread_create(&t, NULL, mythread, &args);
  • Inside the start routine, cast back: myarg_t *m = (myarg_t *) arg;.

Lifetime

sequenceDiagram
  participant P as Parent
  participant T as Child thread
  P->>T: pthread_create(fn, &args)
  T->>T: fn(args) runs
  T-->>P: returns void *retval
  P->>T: pthread_join(t, &retval)
  • The caller owns the storage you point arg at. If args lives on the parent’s stack and the parent returns before the child reads it, the child reads garbage.
  • A thread returning a pointer into its own stack is just as broken — the stack unwinds at exit. Use heap or a caller-owned buffer.

Error reporting

  • pthread_create returns the error code directly (0 on success).
  • Does not touch errno. Reading errno after pthread_create is a bug.
  • Common failure: EAGAIN (system out of resources for another thread).

Quiz yourself

  • When you need multiple arguments, what does the canonical pattern look like?
  • Why is returning a pointer to a stack variable from a thread dangerous?