Start here
User-level vs kernel-level threads
Kernel-level (1:1) maps each library thread to a kernel schedulable entity (typical Linux NPTL). Blocking in read blocks only that thread.
User-level (many-to-one) multiplexes many user threads on fewer kernel threads; switching avoids syscall overhead but a blocking syscall can pin the only underlying kthread unless the runtime works around it.
By the end of this page you should be able to
- State the blocking risk of many-to-one models.
- Explain what “kernel visibility” buys you for SMP scaling.
- Name one modern technique runtimes use to avoid syscall stalls (e.g. pollers, io_uring).
Hybrid (M:N) tries to combine benefits: many user tasks run on a pool of kernel threads, migrating runnable work when a syscall blocks.
Operating systems · Threads
User-level vs kernel-level threads
Who schedules what
TL;DR
User-level threads are multiplexed in user space without kernel awareness (historical green threads); kernel threads are what the OS scheduler actually dispatches. Models: 1:1 (most pthreads on Linux), M:1, M:N, tradeoff between syscall blocking and scheduler control.
Summary
This topic explains why “I created 100k threads” behaves differently by platform and runtime. Tie answers to blocking points, parallelism, and observability in `top`.
Deeper narrative
User-level threads can switch without syscall overhead but block entirely if one thread blocks in the kernel on a 1:1-less model. Green threads historically lost to blocking I/O; modern runtimes integrate pollers and non-blocking I/O to compensate.
Mechanism (step by step)
User-level scheduler
Runtime picks coroutines without entering kernel, fast yield.
Kernel visibility
Without kernel threads, blocking syscall stalls whole user scheduler unless async.
Kernel threads
Scheduler balances across CPUs with standard OS fairness and accounting.
Hybrid
M:N multiplexors migrate runnable work onto idle kthreads when syscalls block.
Key insights
Blocking syscalls
1:1 simplicity
Scheduler leverage
Migration cost
Did you know?
Common pitfalls
Blocking syscall stalls M:N
Must wrap I/O with thread pools or io_uring/async adapters.
Ignoring signal delivery
Signal targeting thread groups differs between models, debug hangs carefully.
Glossary
Green thread
LWP
Poller
Interview follow-ups
- Why did early green threads lose to pthreads for server workloads?
- What does `gettid` reveal under NPTL?
- How does async/await relate to kernel scheduling?
Callouts
Interview trap
Do not claim green threads always avoid kernel, modern runtimes park goroutines onto threads that block.
Walkthrough & deep dive
Left: practical “how would I use this?” threads. Right: slower, code-leaning explanations, open one panel at a time so the page does not feel like a wall of sameness.
Walkthrough
Compare
Deep dive
Scheduler activation (historical)
Kernel upcalls could unblock user-level schedulers, complex; largely replaced by better 1:1 kernels and io_uring.
Kernel threads visible
ps -eLo pid,tid,class,rtprio,comm | head
Self-check
1Kernel threads are scheduled by…
2Pure M:1 user threads struggle when…
3Linux pthreads are typically…