Skip to main content
RunBook Academy

LinuxVI · ProcessesThreads

Threads and cgroup views

Intermediate⏱ ~8 minbashpstopcat

What you'll learn

  • Distinguish a thread from a process
  • Use ps -L and /proc/<pid>/task to inspect threads
  • Understand how cgroup views expose resource accounting per-process
  • Apply thread-level debugging for CPU-saturated processes

Prerequisites

Verified against Ubuntu 24.04 LTS · Debian 12 (Bookworm) · RHEL 9.x · Rocky Linux 9.x · AlmaLinux 9.x · Linux kernel 6.1 LTS / 6.6 LTS · systemd 255+ · OpenSSH 8.7p1 (RHEL 9) / 9.6p1 (Ubuntu 24.04) · nftables 1.0.x · chrony 4.x · Pacemaker 2.1.x · Corosync 3.1.x · 2026-08-09

Not yet marked complete on this device.

Many production processes are multithreaded. nginx, mysqld, Java applications, and most modern daemons have many threads sharing one address space. The kernel tracks each thread as a separate schedulable entity with its own TID; the set of threads is the process.

Threads from ps

Read-only / Safeps -L
$ ps -L -p 1234
  PID   LWP   TID  STAT   TIME COMMAND
12345 12345 12345 Sl   00:00:00 nginx: master process
12345 12346 12346 Sl   00:00:00 nginx: worker process
12345 12347 12347 Sl   00:00:00 nginx: worker process
12345 12348 12348 Sl   00:00:00 nginx: worker process

Illustrative output

Read-only / Safe/proc/<pid>/task
$ ls /proc/12345/task/ | head
12345
12346
12347
12348

Illustrative output

Threads vs processes

PropertyProcessThread
Address spaceIndependentShared
File descriptorsIndependentShared (in most threads)
PIDOne per processOne per thread (the TID)
SchedulingIndependentIndependent
Signal handlersIndependentProcess-wide
Resource accountingPer-processPer-thread (CPU time) but per-cgroup (memory)

Resource accounting with cgroups v2

The kernel’s process accounting is split between two layers:

  • Per-task (per-thread): CPU time, scheduling state, signals. Visible in /proc/<pid>/stat and top -H.
  • Per-cgroup: memory, I/O, PIDs, network. Visible in /sys/fs/cgroup/<controller>/<path>/.

For a multi-threaded process, the memory and I/O accounting is shared across all threads (one cgroup). CPU time is per-thread.

Read-only / Safecgroup memory
$ cat /sys/fs/cgroup/system.slice/sshd.service/memory.current
4194304

Illustrative output

Read-only / Safesystemd-cgtop
$ systemd-cgtop
Control Group                          Tasks   %CPU   Memory
/                                          234    12.5   1.2G
/system.slice                             168    10.0   900M
/system.slice/sshd.service                 4      0.1   16M
/user.slice/alice.service                  12     1.2   200M
...

Illustrative output

Inspecting thread-level CPU usage

Read-only / Safetop -H
$ top -H -p 1234
top - 12:00:00 up 30 days,  3:45,  1 user,  load average: 4.20, 3.10, 2.50
Threads:   4 total,   1 running,   3 sleeping
PID   USER   PR  NI   VIRT   RES   SHR  S  %CPU  %MEM     TIME+  COMMAND
12345  root   20   0  1234m  456m  123m  R  95.0   1.1   0:42.15  nginx: master
12346  www-d  20   0  1234m  456m  123m  S   2.0   1.1   0:01.20  nginx: worker
12347  www-d  20   0  1234m  456m  123m  S   1.5   1.1   0:01.05  nginx: worker
12348  www-d  20   0  123m  45m  12m  S   0.5   0.1   0:00.30  nginx: worker

Illustrative output

Setting thread affinity

Configuration changetaskset
$ taskset -cp 1234; taskset -cp 0-3 1234
pid 1234's current affinity mask: 0-3
pid 1234's current affinity mask: 0-3

Illustrative output

Production use of cgroups

cgroups are how systemd enforces resource limits:

[Service]
CPUQuota=200%
MemoryMax=2G
IOWeight=100

These directives write to the cgroup’s cpu.max, memory.max, and io.weight files. systemd translates the high-level directives to the underlying kernel interface.

Knowledge check

Knowledge check · 3 questions

  1. Q1. How are threads implemented in the Linux kernel?

  2. Q2. CPU time is accounted per-thread; memory is accounted per-cgroup.

  3. Q3. Which of the following statements about cgroups are correct? Select all that apply.

Passing score: 75%. Answers are checked in this browser.