Home / Alt manpages / proc_thread-self(5)

  • proc_thread-self(5)
  • File format
  • linux

Inspect Linux Threads Safely Through /proc

You will identify a process's thread IDs, inspect a particular thread through /proc/PID/task/TID/, and use /proc/thread-self/ without being misled by shell pipelines. Allow about 15 minutes. You need a Linux shell and a readable target process; the examples only read procfs and do not require sudo.

This guide follows the installed manpages package, version 6.7-2, whose manual is Linux man-pages 6.7 dated 15 August 2023. The kernel on this machine is Linux 6.8. The paths described here are kernel interfaces, so output and the set of visible processes are host-specific.

1. Choose a process and record its PID

Start with a process you own, or use a service PID supplied by your normal monitoring procedure. Do not guess a PID from an old incident: processes exit and their numbers are reused. This example uses the current shell's PID, which is safe to inspect:

$ pid=$$
$ printf 'process PID: %s\n' "$pid"
process PID: 432542
$ test -d "/proc/$pid" && echo proc entry exists
proc entry exists

The number in the output is illustrative. Re-run the commands on your host and keep the value in the same shell. Reading procfs is normally unprivileged, although another user's process may expose less information because of permissions or system security policy.

2. List the process's thread IDs

/proc/PID/task/ contains one directory per thread. Each directory name is a TID, or thread ID. A single-threaded process normally has one entry whose number equals its PID:

$ printf 'thread IDs for PID %s:\n' "$pid"
thread IDs for PID 432542:
$ for task in "/proc/$pid"/task/*; do
>     basename "$task"
> done
432542

For a multithreaded process, expect several numbers. Use an exact PID when examining a service. A glob that matches nothing is not evidence that the process has no threads; it usually means the process exited, the PID was wrong, or access was denied.

Checkpoint

You have a live PID and at least one TID copied from that PID's own task directory. Continue with one of those TIDs, not a number copied from a different process.

3. Read information for one thread

Every task directory exposes files with the same names as the corresponding process directory. Some values are shared by all threads, while other values are specific to the selected thread. status is a useful first inspection point:

$ tid=432542
$ sed -n '1,12p' "/proc/$pid/task/$tid/status"
Name:   bash
Umask:  0022
State:  S (sleeping)
Tgid:   432542
Ngid:   0
Pid:    432542
PPid:   431900
TracerPid:      0
Uid:    1000    1000    1000    1000
Gid:    1000    1000    1000    1000
FDSize: 256
Groups: 4 24 27 30 46 122 134 142 144 155

The exact fields, names and values depend on the kernel and process. The useful relationship is Tgid, the thread group or process ID, versus Pid, the selected thread ID. Do not treat a sample name or state as a default.

Compare the thread view with the process view when you need to decide whether a value is shared:

$ sed -n -e '/^Name:/p' -e '/^Tgid:/p' -e '/^Pid:/p' \
>     "/proc/$pid/task/$tid/status" "/proc/$pid/status"
Name:   bash
Tgid:   432542
Pid:    432542
Name:   bash
Tgid:   432542
Pid:    432542

For a non-leader thread, the selected Pid can differ from Tgid. Files such as cwd commonly reflect process-wide state because threads share a working directory, while status fields can differ. The manual does not promise that every file exists in the parent directory when it is meaningful only for a thread.

4. Use the shorthand /proc/TID/ carefully

For a running thread that is not the thread-group leader, /proc/TID/ exposes the same information as /proc/PID/task/TID/. It is a pathname interface, not a directory you can reliably discover with ls /proc:

$ test -d "/proc/$pid/task/$tid" || exit 1
$ if [ "$tid" -ne "$pid" ]; then
>     sed -n '1,8p' "/proc/$tid/status"
> else
>     echo 'TID is the group leader; use /proc/PID/task/TID'
> fi
TID is the group leader; use /proc/PID/task/TID

The branch matters. The manual says non-leader /proc/TID directories are hidden when iterating through /proc, so ordinary ls does not list them even though system calls can use their paths. Prefer the explicit /proc/PID/task/TID/ form in scripts and incident notes because it records which process owns the thread.

5. Understand /proc/thread-self/ in pipelines

/proc/thread-self/ refers to the thread that accesses procfs. It is equivalent to /proc/self/task/TID/ for that accessing thread, and has existed since Linux 3.17. This is useful inside a program that wants its own thread data without first discovering its TID.

The confusing part is that "self" means the process making the individual system call. It does not necessarily mean the shell that launched a command. In this example, readlink performs the read, so the number belongs to that short-lived command:

$ readlink /proc/thread-self
432547/task/432547

Do not save that TID and assume it identifies your interactive shell. A pipeline has the same trap: a program reading /proc/thread-self/status sees its own thread, not the shell's. When you need a stable target, keep using the explicit /proc/$pid/task/$tid/ path captured in step 2.

6. Handle disappearing processes

Procfs is live. A thread can exit between listing task and opening its status file, and a multithreaded process's task directory may be unavailable after its main thread has terminated. Treat No such file or directory as a race or stale target first, not as proof that the kernel has lost the thread.

$ if [ -r "/proc/$pid/task/$tid/status" ]; then
>     sed -n '1,12p' "/proc/$pid/task/$tid/status"
> else
>     printf 'thread %s is no longer readable\n' "$tid" >&2
> fi
thread 432542 is no longer readable

For repeatable diagnostics, record the PID, TID and timestamp, then retry the complete lookup against a fresh process snapshot. Do not turn a missing proc entry into a destructive recovery action or restart a service solely because an observation raced with normal thread exit.

Done means

  • You selected a live PID and obtained TIDs from its own task directory.
  • You can inspect one thread with /proc/PID/task/TID/status and distinguish Pid from Tgid.
  • You know that /proc/TID/ is usable by pathname but hidden from normal ls /proc iteration.
  • You understand that /proc/thread-self/ follows the thread performing the filesystem access, including short-lived pipeline commands.
  • You treat disappearing entries and a terminated main thread as live-process races, then take a fresh snapshot.