A server creates one new joinable thread per request using pthread_create() but never calls pthread_join(). After serving thousands of requests, what is the likely consequence?
AThe server crashes immediately when thread limit is reached, because the OS kills orphaned threads
BPerformance improves because threads exit and free themselves automatically once the function returns
CThread resources (stack, metadata) accumulate without being freed, eventually exhausting memory or hitting OS thread limits
DThe threads keep running in the background, completing their work but logging errors
A joinable POSIX thread that terminates does NOT automatically free its resources. Like a zombie process waiting for its parent to call wait(), a joinable thread waits for another thread to call pthread_join() before releasing its stack and metadata. If pthread_join() is never called, those resources accumulate with each completed request. After enough requests, the process runs out of memory or hits the OS's thread count limit, causing new thread creations to fail. The fix is either to call pthread_join() after each thread completes, or to create threads as detached (pthread_detach), allowing the OS to reclaim resources automatically.
Question 2 Multiple Choice
Which of the following is NOT shared between threads in the same process?
AHeap memory (dynamically allocated objects)
BOpen file descriptors
CEach thread's own call stack
DThe program's code (text segment)
Threads in the same process share the heap, open file descriptors, global variables, and the code segment — this shared address space is what makes threads 'lightweight' compared to processes and what makes inter-thread communication fast. However, each thread has its own stack: its local variables, function call frames, and return addresses are private to that thread. This is why local variables are thread-safe by default (different threads can't accidentally clobber each other's stack frames), while heap-allocated objects and globals require explicit synchronization. Each thread also has its own program counter and register set, so threads can execute different code paths simultaneously.
Question 3 True / False
A joinable thread that has called pthread_exit() and terminated still holds memory resources until another thread calls pthread_join() on it.
TTrue
FFalse
Answer: True
This is the POSIX threading equivalent of zombie processes. pthread_exit() ends thread execution and allows the thread to return a value — but 'joinable' means the thread's stack, thread ID, and return value are preserved so that another thread can retrieve them via pthread_join(). Only after pthread_join() is called does the OS release those resources. Forgetting to join joinable threads is a classic resource leak. The alternative design is a detached thread (created with PTHREAD_CREATE_DETACHED or detached via pthread_detach()): detached threads release resources automatically on exit, but their return value cannot be retrieved.
Question 4 True / False
Calling pthread_exit() in a thread is equivalent to calling pthread_detach() on it — both cause the thread's resources to be freed immediately upon exit.
TTrue
FFalse
Answer: False
pthread_exit() and pthread_detach() are distinct operations with different effects. pthread_exit() terminates the calling thread and may pass a return value — but whether resources are freed immediately depends on whether the thread is joinable or detached. For a joinable thread, pthread_exit() terminates execution while resources remain until pthread_join() is called. pthread_detach() changes a thread's joinability state from joinable to detached, causing the OS to free resources automatically at exit (but making it unjoinable). A detached thread calling pthread_exit() will have its resources freed immediately. A joinable thread calling pthread_exit() will not.
Question 5 Short Answer
Explain the difference between a joinable and a detached thread in POSIX. What are the resource consequences of each design, and when would you choose detached over joinable?
Think about your answer, then reveal below.
Model answer: A joinable thread (the default) preserves its stack and return value after exiting until another thread calls pthread_join(), which retrieves the return value and frees resources. A detached thread releases resources automatically when it exits but cannot be joined. Use joinable when you need the thread's return value or need to know it has completed before proceeding. Use detached for fire-and-forget threads (e.g., worker threads in a pool) where you don't need results and want the OS to handle cleanup automatically.
The choice is about who manages the thread's lifetime. Joinable threads give the parent control — it can wait for completion and inspect results — but impose a responsibility: every joinable thread must be joined exactly once, or resources leak. Detached threads are simpler to manage for long-running systems where tracking individual thread completions is impractical (like a server spawning thousands of request handlers), but they sacrifice the ability to synchronize on completion or retrieve return values. Thread pools are a common third option: a fixed set of joinable worker threads are managed centrally, avoiding both the overhead of thread creation and the resource-leak risk of unjoined threads.