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 like CLONE_VM, CLONE_FS, CLONE_FILES, and CLONE_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() or kthread_run() inside kernel space.
  • No User-Space Address Space: task->mm is NULL (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 aux or top with 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]

  1. Many-to-One: Lightweight user-space management, but zero true multi-core CPU parallelism.
  2. One-to-One (Linux Default): Every pthread gets a dedicated task_struct scheduled by the kernel (completely fair scheduler / EEVDF).
  3. 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.
Loading...