Learn POSIX Threads (pthreads) in Linux: thread creation, synchronization, mutexes, condition variables, and advanced concepts with practical examples & interview tips.
Multithreading is a fundamental concept in modern software development, especially in high-performance, real-time, and concurrent applications. POSIX Threads, commonly called pthreads, is the standard threading library in Unix/Linux systems. This article will give you a complete understanding of pthreads from basics to advanced concepts, with examples, diagrams, and interview tips.
1. Introduction to POSIX Threads
What are Threads?
- A thread is the smallest unit of execution within a process.
- Multiple threads can exist within the same process, sharing code, data, and resources like file descriptors and heap memory.
- Each thread has its own stack, program counter (PC), and registers.
Example: A web server can use one thread per client request, sharing the same memory space for efficient communication.
Difference Between Processes and Threads
| Feature | Process | Thread |
|---|---|---|
| Memory | Separate memory space | Shares memory with other threads |
| Overhead | Higher (context switching) | Lower |
| Communication | Inter-process communication (IPC) | Direct memory access |
| Creation | fork() | pthread_create() |
| Use-case | Isolation, heavy tasks | Lightweight, concurrent tasks |
Interview Tip: Be ready to explain why threads are faster than processes for certain tasks, citing shared memory and low creation overhead.
Advantages and Use-Cases of Multithreading
Advantages:
- Responsiveness: GUI apps remain responsive while performing background tasks.
- Resource sharing: Threads share process memory, enabling easy communication.
- Better CPU utilization: Threads can run concurrently on multiple cores.
- Simplified program structure: Tasks like I/O and computation can run in parallel.
Use-Cases:
- Web servers and database servers
- Real-time embedded systems
- Parallel computation tasks (matrix multiplication, video processing)
- Producer-consumer pipelines
2. POSIX Threads Library Overview
What is pthreads?
- POSIX Threads is a standard API for multithreading on Unix-like systems.
- Implemented in
. - Supports thread creation, synchronization, attributes, cancellation, and real-time scheduling.
Including pthread library in C/C++ programs
#include
#include
#include
- Compiling programs requires linking the pthread library:
gcc myprogram.c -o myprogram -lpthread
3. Thread Creation and Termination
Using pthread_create()
void* thread_function(void* arg) {
printf("Hello from thread! Received: %d\n", *(int*)arg);
pthread_exit((void*) arg); // Exit thread and return value
}
int main() {
pthread_t tid;
int value = 42;
// Create a thread
if (pthread_create(&tid, NULL, thread_function, (void*)&value) != 0) {
perror("pthread_create failed");
exit(1);
}
void* ret_val;
pthread_join(tid, &ret_val); // Wait for thread to finish
printf("Thread returned: %d\n", (int)(long)ret_val);
return 0;
}
Explanation:
pthread_t tid: Thread ID.pthread_create(): Creates a thread.- Arguments: Thread ID, attributes (NULL = default), thread function, arguments.
pthread_exit(): Ends the thread.pthread_join(): Waits for a thread and retrieves its return value.
Interview Tip: Know the difference between pthread_exit() and return in a thread function.
4. Thread Attributes
- pthread_attr_t is used to customize threads.
Common attributes:
- Stack size:
pthread_attr_setstacksize() - Detach state: Joinable or detached (
pthread_attr_setdetachstate()) - Scheduling policy:
SCHED_FIFO,SCHED_RR,SCHED_OTHER
Example:
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setstacksize(&attr, 1024*1024); // 1 MB
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
pthread_create(&tid, &attr, thread_function, (void*)&value);
pthread_attr_destroy(&attr);
5. Thread Detachment
- Joinable Threads: Must be joined using
pthread_join(). - Detached Threads: Resources are automatically released when the thread exits.
pthread_detach(tid); // Detaches a joinable thread
Interview Tip: Explain the memory/resource leak problem if detached threads are not properly used.
6. Thread Synchronization
Multithreading introduces the risk of race conditions. Synchronization primitives prevent this.
Mutexes (pthread_mutex_t)
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_lock(&lock); // Acquire lock
// Critical section
pthread_mutex_unlock(&lock); // Release lock
pthread_mutex_destroy(&lock);
- Recursive Mutex: Same thread can lock multiple times.
Condition Variables (pthread_cond_t)
- Used for signaling between threads.
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
// Thread A waits
pthread_mutex_lock(&lock);
pthread_cond_wait(&cond, &lock); // Releases lock and waits
pthread_mutex_unlock(&lock);
// Thread B signals
pthread_mutex_lock(&lock);
pthread_cond_signal(&cond);
pthread_mutex_unlock(&lock);
- Broadcast wakes all waiting threads:
pthread_cond_broadcast()
Reader-Writer Locks
pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;
pthread_rwlock_rdlock(&rwlock); // Acquire read lock
pthread_rwlock_wrlock(&rwlock); // Acquire write lock
pthread_rwlock_unlock(&rwlock);
7. Thread-Specific Data (TSD)
- Each thread can have its own private data using
pthread_key_t.
pthread_key_t key;
pthread_key_create(&key, free);
void* val = malloc(sizeof(int));
*(int*)val = 100;
pthread_setspecific(key, val);
int* myval = (int*)pthread_getspecific(key);
printf("Thread-specific data: %d\n", *myval);
8. Thread Cancellation and Cleanup
Thread Cancellation
pthread_cancel(tid); // Request thread termination
- Types: Asynchronous (immediate) or Deferred (at cancellation points)
Cleanup Handlers
void cleanup(void* arg) { printf("Cleaning: %s\n", (char*)arg); }
pthread_cleanup_push(cleanup, "Thread resources");
pthread_cleanup_pop(1); // Execute cleanup
9. Advanced Thread Topics
Scheduling Policies and Priorities
SCHED_FIFO: First-in-first-out real-timeSCHED_RR: Round-robin real-timeSCHED_OTHER: Default Linux timesharing
Signal Handling
- Signals can be masked per-thread using
pthread_sigmask().
Deadlocks
- Avoid nested locks
- Use
pthread_mutex_trylock()to prevent waiting forever - Lock ordering strategy
10. Best Practices and Interview Tips
- Always initialize and destroy mutexes, condition variables.
- Prefer joinable threads if you need a return value.
- Avoid sharing mutable global variables without synchronization.
- Minimize critical section to improve performance.
- Use thread-specific data to avoid data races.
- Understand pthread attribute usage for real-time and embedded systems.
- Be ready to explain common pitfalls like deadlocks, resource leaks, and race conditions.
11. Example Programs
Simple Thread Creation
#include
#include
void* say_hello(void* arg) {
printf("Hello from thread!\n");
return NULL;
}
int main() {
pthread_t tid;
pthread_create(&tid, NULL, say_hello, NULL);
pthread_join(tid, NULL);
return 0;
}
Producer-Consumer Problem
#include
#include
#include
#define BUFFER_SIZE 5
int buffer[BUFFER_SIZE], count = 0;
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t not_empty = PTHREAD_COND_INITIALIZER;
pthread_cond_t not_full = PTHREAD_COND_INITIALIZER;
void* producer(void* arg) {
for (int i=0;i<10;i++){
pthread_mutex_lock(&lock);
while(count == BUFFER_SIZE) pthread_cond_wait(¬_full, &lock);
buffer[count++] = i;
printf("Produced: %d\n", i);
pthread_cond_signal(¬_empty);
pthread_mutex_unlock(&lock);
}
return NULL;
}
void* consumer(void* arg) {
for(int i=0;i<10;i++){
pthread_mutex_lock(&lock);
while(count == 0) pthread_cond_wait(¬_empty, &lock);
int val = buffer[--count];
printf("Consumed: %d\n", val);
pthread_cond_signal(¬_full);
pthread_mutex_unlock(&lock);
}
return NULL;
}
int main() {
pthread_t p, c;
pthread_create(&p, NULL, producer, NULL);
pthread_create(&c, NULL, consumer, NULL);
pthread_join(p, NULL);
pthread_join(c, NULL);
return 0;
}
Thread-Specific Data Example
pthread_key_t key;
void* thread_func(void* arg) {
int* val = malloc(sizeof(int));
*val = *(int*)arg;
pthread_setspecific(key, val);
printf("Thread-specific data: %d\n", *(int*)pthread_getspecific(key));
return NULL;
}
POSIX Threads (pthreads) Interview Questions
1. Basics of Threads and Pthreads
Beginner Questions
- What is a thread? How does it differ from a process?
- What are the advantages of using threads over processes?
- Explain multithreading with an example.
- What is POSIX Threads (pthreads)? Why is it used?
- How do you include pthread library in a C/C++ program?
- How do you compile a pthread program in Linux? (
-lpthread) - What is the difference between user-level threads and kernel-level threads?
- Can threads share memory? Which resources are shared, and which are private?
Intermediate Questions
9. Explain the thread lifecycle (New, Runnable, Running, Waiting, Terminated).
10. What is a thread ID (pthread_t)? How is it used?
11. What is a joinable thread vs a detached thread?
Advanced Questions
12. Explain the differences between POSIX threads and Windows threads.
13. What are some common pitfalls when using threads in Linux?
2. Thread Creation and Termination
Beginner Questions
- How do you create a thread in pthreads? Explain
pthread_create()arguments. - What is the prototype of a thread function?
- How do threads terminate? Difference between
pthread_exit()and returning from thread function. - How do you wait for a thread to finish? Explain
pthread_join().
Intermediate Questions
5. Can a thread return a value? How?
6. What happens if pthread_join() is not called for a joinable thread?
7. What is the effect of calling exit() inside a thread?
Advanced Questions
8. How can you handle multiple threads returning different data types?
9. Explain thread stack allocation and stack size management.
3. Thread Attributes (pthread_attr_t)
Beginner Questions
- What are thread attributes? Why are they used?
- How do you initialize and destroy thread attributes? (
pthread_attr_init,pthread_attr_destroy)
Intermediate Questions
3. How do you set a thread as detached using attributes?
4. How do you set a custom stack size?
5. How do you set scheduling policy using attributes? (SCHED_FIFO, SCHED_RR, SCHED_OTHER)
Advanced Questions
6. What are real-time thread attributes and their significance?
7. How do thread attributes affect performance and memory usage?
4. Thread Detachment
Beginner Questions
- What is the difference between detached and joinable threads?
- How do you detach a thread after creation? (
pthread_detach)
Intermediate Questions
3. What happens if a detached thread calls pthread_exit()?
4. Can you join a detached thread? Why or why not?
Advanced Questions
5. When should you use detached threads in real-world applications?
5. Thread Synchronization
Mutexes
Beginner Questions
- What is a mutex? Why is it needed?
- How do you initialize, lock, unlock, and destroy a mutex?
- What happens if a thread tries to unlock a mutex it does not own?
Intermediate Questions
4. What is a recursive mutex? When is it used?
5. Explain deadlocks with an example in multithreaded programs.
6. How can deadlocks be avoided in pthread programs?
Advanced Questions
7. Explain priority inversion and how to handle it in pthreads.
Condition Variables
Beginner Questions
- What is a condition variable?
- How do
pthread_cond_wait(),pthread_cond_signal(), andpthread_cond_broadcast()work?
Intermediate Questions
3. Why do you need a mutex with condition variables?
4. What is spurious wakeup, and how do you handle it?
Advanced Questions
5. Explain producer-consumer problem using mutex and condition variables.
Reader-Writer Locks
Beginner Questions
- What is a reader-writer lock (
pthread_rwlock_t)? - How is it different from a mutex?
Intermediate Questions
3. How do you acquire read and write locks? (pthread_rwlock_rdlock, pthread_rwlock_wrlock)
4. What happens if multiple writers try to acquire the lock simultaneously?
6. Thread-Specific Data (TSD)
Beginner Questions
- What is thread-specific data?
- How do you create a
pthread_key_t?
Intermediate Questions
3. How do you set and get thread-specific data? (pthread_setspecific, pthread_getspecific)
4. How is thread-specific data useful in real applications?
Advanced Questions
5. How do you cleanup thread-specific data automatically?
7. Thread Cancellation and Cleanup
Beginner Questions
- How do you cancel a thread? (
pthread_cancel) - What is the difference between asynchronous and deferred cancellation?
Intermediate Questions
3. How do you set a thread as cancellable or non-cancellable?
4. What are cleanup handlers? (pthread_cleanup_push, pthread_cleanup_pop)
Advanced Questions
5. How do you ensure resources are freed when a thread is cancelled?
8. Advanced Thread Topics
Scheduling and Real-time
Beginner Questions
- What are the POSIX thread scheduling policies? (
SCHED_FIFO,SCHED_RR,SCHED_OTHER) - How do you set thread priority?
Intermediate Questions
3. How is real-time scheduling different from normal scheduling?
4. What are the limitations of real-time threads in Linux?
Signal Handling in Threads
- How are signals delivered in multithreaded programs?
- How do you block/unblock signals for a thread? (
pthread_sigmask)
Deadlocks
- What is a deadlock?
- How can you detect and prevent deadlocks?
- Explain lock hierarchy and timeout-based strategies.
9. Best Practices Questions
- What are common pitfalls in pthread programming?
- How do you avoid race conditions?
- How should multithreaded programs be structured for safety and efficiency?
- How do you optimize performance in multithreaded programs?
- How do you debug pthread programs? (
gdb,helgrind,valgrind)
10. Practical and Coding Questions (Interview-Focused)
- Write a simple program that creates multiple threads and prints messages.
- Implement a producer-consumer problem using mutexes and condition variables.
- Implement a thread-safe counter using mutex or atomic operations.
- Demonstrate using thread-specific data.
- Write a program where threads are detached and cannot be joined.
- Simulate deadlock and show how to fix it.
- Demonstrate cancelling a thread and cleaning up resources.
- Implement a reader-writer scenario using
pthread_rwlock_t.
Conclusion
- POSIX threads allow efficient, lightweight multithreading in Linux.
- Key interview topics:
pthread_create,pthread_join, mutexes, condition variables, thread attributes, thread cancellation, TSD, and deadlock avoidance. - Practice coding small multithreaded programs, and always reason about synchronization and data sharing.
- Advanced topics: Real-time scheduling, signal handling, and performance optimization are often asked in senior-level interviews.
Recommended Resources:
- “Programming with POSIX Threads” by David R. Butenhof
- Linux man pages:
man pthread_create,man pthread_mutex_lock - Online tutorials and example repositories on GitHub
FAQ : POSIX Threads (pthreads)
1. What are POSIX Threads (pthreads) in Linux?
Answer:
POSIX Threads, or pthreads, are a standardized way to create and manage multithreaded programs in Linux. Threads allow a program to execute multiple tasks concurrently within the same process, sharing memory and resources while maintaining separate execution contexts.
2. How do I create a thread using pthreads in C/C++?
Answer:
You create a thread using pthread_create(). It requires a thread ID, optional thread attributes, the thread function, and an argument. Example:
pthread_t tid;
pthread_create(&tid, NULL, thread_function, (void*)&arg);
This starts a new thread executing thread_function.
3. What is the difference between processes and threads?
Answer:
- Processes have separate memory spaces, heavier to create, and use IPC to communicate.
- Threads share the same memory space, are lightweight, and communicate directly through shared variables.
Threads are ideal for concurrent execution, while processes are better for isolation and fault tolerance.
4. How can I wait for a thread to finish in pthreads?
Answer:
Use pthread_join() to wait for a joinable thread to complete and optionally retrieve its return value:
void* retval;
pthread_join(tid, &retval);
Detached threads cannot be joined, and their resources are automatically freed after completion.
5. What are pthread mutexes and why are they important?
Answer:
A mutex (mutual exclusion) is a synchronization primitive used to prevent race conditions when multiple threads access shared data. Operations include lock, unlock, and destroy:
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_lock(&lock); // Critical section
pthread_mutex_unlock(&lock);
6. What is the purpose of condition variables in pthreads?
Answer:
Condition variables allow threads to wait for certain conditions before proceeding, typically used with mutexes. They support signaling one or all threads when a condition changes:
pthread_cond_wait(&cond, &mutex);
pthread_cond_signal(&cond);
pthread_cond_broadcast(&cond);
Use-case: Implementing producer-consumer problems.
7. What is thread-specific data (TSD) in pthreads?
Answer:
Thread-specific data allows each thread to store its own private data using a key (pthread_key_t), even if multiple threads run the same function:
pthread_key_t key;
pthread_setspecific(key, data);
void* val = pthread_getspecific(key);
This is useful for per-thread storage in libraries or reusable modules.
8. How do you cancel a thread safely in pthreads?
Answer:
Use pthread_cancel() to request thread termination. Threads can be asynchronous or deferred cancellable, and you can use cleanup handlers to release resources:
pthread_cleanup_push(cleanup_function, arg);
pthread_cleanup_pop(1);9. What are detached threads and how are they different from joinable threads?
Answer:
- Joinable threads require
pthread_join()to free resources. - Detached threads free resources automatically when they finish.
Usepthread_detach(tid)to detach a thread. Detached threads are ideal for background tasks where you don’t need the return value.
10. What are common pitfalls in pthread programming?
Answer:
- Race conditions due to unsynchronized shared memory.
- Deadlocks caused by nested or circular locking.
- Forgetting to destroy mutexes/condition variables.
- Improper use of detached threads leading to memory/resource leaks.
- Ignoring thread cancellation and cleanup.
Best Practice: Always use mutexes, condition variables, and cleanup handlers for safe multithreaded programs.
Read More : IPC in Linux
Mr. Raj Kumar is a highly experienced Technical Content Engineer with 7 years of dedicated expertise in the intricate field of embedded systems. At Embedded Prep, Raj is at the forefront of creating and curating high-quality technical content designed to educate and empower aspiring and seasoned professionals in the embedded domain.
Throughout his career, Raj has honed a unique skill set that bridges the gap between deep technical understanding and effective communication. His work encompasses a wide range of educational materials, including in-depth tutorials, practical guides, course modules, and insightful articles focused on embedded hardware and software solutions. He possesses a strong grasp of embedded architectures, microcontrollers, real-time operating systems (RTOS), firmware development, and various communication protocols relevant to the embedded industry.
Raj is adept at collaborating closely with subject matter experts, engineers, and instructional designers to ensure the accuracy, completeness, and pedagogical effectiveness of the content. His meticulous attention to detail and commitment to clarity are instrumental in transforming complex embedded concepts into easily digestible and engaging learning experiences. At Embedded Prep, he plays a crucial role in building a robust knowledge base that helps learners master the complexities of embedded technologies.










