pthread vs kthread
Conceptual OS Thread Comparison
| Dimension | User-Space Threads | Kernel-Space Threads |
|---|---|---|
| Management | User-space runtime/library (e.g., green threads, Go goroutines, fiber libs) | OS Kernel Scheduler |
| Kernel Awareness | No — kernel only sees the parent container process/task | Yes — individual execution entity tracked by kernel |
| Context Switch Cost | Very Low — simple register save/restore in user space (no privilege shift) | Higher — involves ring switch / CPU state management |
| Blocking Behavior | If a user thread makes a blocking OS call, the entire kernel thread backing it blocks (unless async I/O is used) | Blocking one thread leaves other kernel threads free to run on other CPU cores |
| Multi-Core Parallelism | Cannot utilize multiple CPU cores without mapping to underlying kernel threads | Directly scheduled across multiple physical/logical CPU cores |
Linux Kernel Architecture Perspective
In Modern Linux, execution entities are represented by struct task_struct.
User-Space Threads (NPTL / pthread)
The "p" in pthread stands for POSIX (Portable Operating System Interface).
- Created via
clone(2)with flags likeCLONE_VM,CLONE_FS,CLONE_FILES, andCLONE_SIGHAND. - Have both a User Stack (in user virtual memory) and a Kernel Stack (used when handling syscalls or page faults).
- Run in Ring 3 (User Space) during normal execution, switching to Ring 0 (Kernel Space) temporarily via syscalls.
- Mapped 1:1 to kernel scheduling entities in Linux (Native POSIX Thread Library).
Linux Kernel Threads (kthread)
- Spawned using
kthread_create()orkthread_run()inside kernel space. - No User-Space Address Space:
task->mmisNULL(they share the kernel page tables and do not map user-space virtual memory). - Kernel-Only Execution: Run exclusively in Ring 0 (Kernel Space).
- Have only a Kernel Stack (typically 8KB or 16KB depending on architecture).
- Visible in
ps auxortopwith bracketed names (e.g.,[kthreadd],[kworker/0:1],[ksoftirqd/0]). - Perform OS background work like deferred interrupt processing, memory reclamation, filesystem syncing, and driver workqueues.
The Three Multi-Threading Mapping Models
1. Many-to-One (Green Threads) 2. One-to-One (Native Linux pthreads) 3. Many-to-Many (Go Runtime / Goroutines)
[User Thread] [User Thread] [User Thread] [User Thread] [User Thread] [User Thread] [User Thread]
\ / | | \ | /
[User Runtime Scheduler] | | [User Runtime Scheduler]
| | | / \
[Kernel Thread] [Kernel Thread] [Kernel Thread] [Kernel Thread] [Kernel Thread]
- Many-to-One: Lightweight user-space management, but zero true multi-core CPU parallelism.
- One-to-One (Linux Default): Every
pthreadgets a dedicatedtask_structscheduled by the kernel (completely fair scheduler/ EEVDF). - Many-to-Many / M:N: Hybrid runtime (like Go's M:N scheduler) multiplexing M user green threads onto N kernel threads to combine low context-switch overhead with full multi-core scalability.