Master Linux Threads: Creation, Control, and Scheduling Explained
This guide explains Linux thread fundamentals, covering definitions, differences from processes, user‑level vs kernel‑level models, creation and termination with pthread APIs, attribute settings, cancellation, cleanup, detaching, and scheduling policies, all illustrated with complete code examples.
Introduction
In modern operating systems a thread is the smallest unit of execution. Threads are lighter than processes, have lower creation and destruction overhead, and can share a process’s memory, making them essential for concurrent programming. Linux provides full POSIX‑compatible thread support, and the following sections describe the core concepts, the Linux thread model, and practical thread‑control techniques with complete code examples.
Basic concepts of threads
Definition: A thread is an execution flow that lives inside a process and shares the process’s address space, file descriptors and other resources.
Resource overhead: Creating or destroying a thread is much cheaper than creating or destroying a process.
Communication: Threads communicate simply by reading and writing shared memory; inter‑process communication (IPC) requires explicit mechanisms.
Context switch: Switching between threads incurs far less overhead than a full process switch.
Independence: Threads depend on their parent process; a fault in one thread can affect the whole process.
Responsiveness: While one thread blocks on I/O, another can continue to run.
Resource sharing: All threads of a process see the same address space, simplifying data exchange.
Efficiency: Thread creation, termination and switching are cheaper than their process equivalents.
Multi‑core utilization: Multiple threads can run simultaneously on different CPU cores.
Synchronization issues: Shared mutable state can lead to race conditions.
Debugging difficulty: Non‑deterministic execution order makes bugs harder to reproduce.
Resource contention: Competing threads may degrade performance if they contend for the same resources.
Linux thread model
User‑level threads: Managed entirely in user space by a threading library (e.g., the POSIX pthread library). The kernel is unaware of these threads, so scheduling and synchronization are performed without kernel involvement. This yields very low overhead but cannot exploit multiple CPUs because the kernel sees only a single execution context.
Kernel‑level threads: Each thread is represented as a distinct kernel object (a lightweight process, LWP). The kernel schedules them on any CPU and provides system‑call based synchronization. Overhead is higher than user‑level threads, but true parallelism on multi‑core systems is possible.
Linux implements threads as LWPs. Every thread created by the POSIX pthread library corresponds to an LWP that shares the same address space and file descriptors with its siblings. The Native POSIX Thread Library (NPTL) supplies the POSIX API on top of these LWPs.
Thread control
Creating and terminating threads
The POSIX thread library provides pthread_create to start a new thread. Its prototype is:
#include <pthread.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine)(void *), void *arg); thread: pointer to a pthread_t that receives the thread identifier. attr: thread attributes (pass NULL for defaults). start_routine: function that the new thread will execute. arg: single argument passed to start_routine.
Simple creation example:
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
void* thread_function(void* arg) {
printf("Thread is running...
");
sleep(2);
printf("Thread is exiting...
");
return NULL;
}
int main() {
pthread_t thread_id;
int ret = pthread_create(&thread_id, NULL, thread_function, NULL);
if (ret != 0) {
printf("Thread creation failed!
");
return 1;
}
printf("Main thread is running...
");
pthread_join(thread_id, NULL);
printf("Main thread is exiting...
");
return 0;
}The main thread waits for the child thread with pthread_join. A thread can terminate in three ways:
Returning from the start routine (normal exit).
Calling pthread_exit explicitly.
Being cancelled by another thread via pthread_cancel.
Explicit termination example:
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
void* thread_function(void* arg) {
printf("Thread is running...
");
sleep(2);
printf("Thread is exiting...
");
pthread_exit(NULL);
}
int main() {
pthread_t thread_id;
int ret = pthread_create(&thread_id, NULL, thread_function, NULL);
if (ret != 0) {
printf("Thread creation failed!
");
return 1;
}
printf("Main thread is running...
");
pthread_join(thread_id, NULL);
printf("Main thread is exiting...
");
return 0;
}Thread attributes
Thread attributes are configured through a pthread_attr_t object. Common attributes include detach state, stack size, and scheduling policy.
Detach state: PTHREAD_CREATE_JOINABLE (default) requires a later pthread_join to reclaim resources; PTHREAD_CREATE_DETACHED releases resources automatically when the thread exits.
Stack size: The default stack can be changed with pthread_attr_setstacksize.
Scheduling policy: Policies such as SCHED_FIFO, SCHED_RR or the default SCHED_OTHER can be set with pthread_attr_setschedpolicy and pthread_attr_setschedparam.
Example that creates a detached thread:
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
void* thread_function(void* arg) {
printf("Thread is running...
");
sleep(2);
printf("Thread is exiting...
");
return NULL;
}
int main() {
pthread_t thread_id;
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
int ret = pthread_create(&thread_id, &attr, thread_function, NULL);
if (ret != 0) {
printf("Thread creation failed!
");
return 1;
}
printf("Main thread is running...
");
sleep(3); // give the detached thread time to finish
printf("Main thread is exiting...
");
pthread_attr_destroy(&attr);
return 0;
}Thread cancellation
A thread can be cancelled by another thread using pthread_cancel. Cancellation occurs at defined cancellation points such as sleep, read, or write.
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
void* thread_function(void* arg) {
printf("Thread is running...
");
while (1) {
printf("Thread is working...
");
sleep(1);
}
return NULL;
}
int main() {
pthread_t thread_id;
int ret = pthread_create(&thread_id, NULL, thread_function, NULL);
if (ret != 0) {
printf("Thread creation failed!
");
return 1;
}
sleep(3);
pthread_cancel(thread_id);
printf("Thread has been canceled.
");
pthread_join(thread_id, NULL);
printf("Main thread is exiting...
");
return 0;
}Thread cleanup
When a thread terminates, it may need to release resources. POSIX provides pthread_cleanup_push and pthread_cleanup_pop to register cleanup handlers that are executed when the thread exits or is cancelled.
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
void cleanup_function(void* arg) {
printf("Cleanup function called: %s
", (char*)arg);
}
void* thread_function(void* arg) {
pthread_cleanup_push(cleanup_function, "Resource 1");
pthread_cleanup_push(cleanup_function, "Resource 2");
printf("Thread is running...
");
sleep(2);
printf("Thread is exiting...
");
pthread_cleanup_pop(1);
pthread_cleanup_pop(1);
return NULL;
}
int main() {
pthread_t thread_id;
int ret = pthread_create(&thread_id, NULL, thread_function, NULL);
if (ret != 0) {
printf("Thread creation failed!
");
return 1;
}
pthread_join(thread_id, NULL);
printf("Main thread is exiting...
");
return 0;
}Thread detaching
A detached thread releases its resources automatically when it terminates, so the creator does not need to call pthread_join. Detached threads cannot be joined later and their return values are not retrievable.
#include <stdio.h>
#include <pthread.h>
#include <unistd.h>
void* thread_function(void* arg) {
printf("Thread is running...
");
sleep(2);
printf("Thread is exiting...
");
return NULL;
}
int main() {
pthread_t thread_id;
int ret = pthread_create(&thread_id, NULL, thread_function, NULL);
if (ret != 0) {
printf("Thread creation failed!
");
return 1;
}
pthread_detach(thread_id);
printf("Main thread is running...
");
sleep(3);
printf("Main thread is exiting...
");
return 0;
}Thread scheduling
SCHED_FIFO: First‑in‑first‑out real‑time policy; a higher‑priority thread runs until it blocks or yields.
SCHED_RR: Round‑robin real‑time policy; threads of equal priority share the CPU in time slices.
SCHED_OTHER: Default Linux time‑sharing scheduler.
Scheduling policy and priority can be set via pthread_attr_setschedpolicy and pthread_attr_setschedparam (or directly with pthread_setschedparam on an existing thread).
#include <stdio.h>
#include <pthread.h>
#include <sched.h>
#include <unistd.h>
void* thread_function(void* arg) {
printf("Thread is running...
");
sleep(2);
printf("Thread is exiting...
");
return NULL;
}
int main() {
pthread_t thread_id;
pthread_attr_t attr;
struct sched_param param;
pthread_attr_init(&attr);
pthread_attr_setschedpolicy(&attr, SCHED_FIFO);
param.sched_priority = 50; // priority range depends on the policy
pthread_attr_setschedparam(&attr, ¶m);
int ret = pthread_create(&thread_id, &attr, thread_function, NULL);
if (ret != 0) {
printf("Thread creation failed!
");
return 1;
}
pthread_join(thread_id, NULL);
printf("Main thread is exiting...
");
pthread_attr_destroy(&attr);
return 0;
}This program creates a thread that runs under the real‑time FIFO policy with priority 50. The main thread waits for its completion with pthread_join.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Liangxu Linux
Liangxu, a self‑taught IT professional now working as a Linux development engineer at a Fortune 500 multinational, shares extensive Linux knowledge—fundamentals, applications, tools, plus Git, databases, Raspberry Pi, etc. (Reply “Linux” to receive essential resources.)
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
