文章目录
- 线程状态以及转换
-
- [1 基本状态](#1 基本状态)
-
- [1.1 新建(New)](#1.1 新建(New))
- [1.2 就绪(Ready / Runnable)](#1.2 就绪(Ready / Runnable))
- [1.3 运行中(Running)](#1.3 运行中(Running))
- [1.4 阻塞/等待(Blocked / Waiting / Sleeping)](#1.4 阻塞/等待(Blocked / Waiting / Sleeping))
- [1.5 挂起(Suspended)](#1.5 挂起(Suspended))
- [1.6 终止(Terminated / Dead / Exit)](#1.6 终止(Terminated / Dead / Exit))
- 注意点
- [2 状态转换](#2 状态转换)
-
- [2.1 C/C++ 线程状态转换图(基于 Linux/POSIX 和 `std::thread`)](#2.1 C/C++ 线程状态转换图(基于 Linux/POSIX 和
std::thread
)) - [2.2 状态转换说明](#2.2 状态转换说明)
- [2.3 示例:多个状态的转换代码](#2.3 示例:多个状态的转换代码)
- [2.1 C/C++ 线程状态转换图(基于 Linux/POSIX 和 `std::thread`)](#2.1 C/C++ 线程状态转换图(基于 Linux/POSIX 和
- [3 调试](#3 调试)
-
- [3.1 Linux 中线程/进程的典型状态码](#3.1 Linux 中线程/进程的典型状态码)
- [3.2 深入 `/proc/[pid]/task/` 查看线程状态](#3.2 深入
/proc/[pid]/task/
查看线程状态) - [3.3 状态之间的实际转换(C++ 映射)](#3.3 状态之间的实际转换(C++ 映射))
- [3.5 调试技巧](#3.5 调试技巧)
- 总结:线程状态的决定者是谁?
线程状态以及转换
线程的基本状态通常用于描述线程在程序执行过程中的生命周期。
1 基本状态
1.1 新建(New)
- 说明:线程对象已经创建,但尚未启动。
- 示例(C++):
std::thread t(myFunction);
(如果尚未调用join()
或detach()
)
1.2 就绪(Ready / Runnable)
- 说明:线程已经准备好运行,但由于 CPU 正忙,暂时未被调度执行。
- 特征:已具备运行条件,等待调度。
1.3 运行中(Running)
- 说明:线程正在由 CPU 调度并执行任务。
- 特征:只有一个线程能在某一时刻占用一个 CPU 核心运行。
1.4 阻塞/等待(Blocked / Waiting / Sleeping)
-
说明:线程暂时无法继续运行,处于等待某些资源或事件状态。
-
常见原因:
- 等待锁(mutex)释放
- 等待条件变量(
std::condition_variable
) - 调用了
sleep_for()
/sleep_until()
- 等待 I/O 操作完成
1.5 挂起(Suspended)
- 说明:线程被人为暂停,暂时不会被调度(某些系统中才存在,如 Windows)。
- 补充:这不是所有系统都显式支持的状态。
1.6 终止(Terminated / Dead / Exit)
-
说明:线程执行完任务或被强制终止,生命周期结束。
-
注意事项:
- 线程终止后不能被重启。
- C++ 中,必须在适当时机调用
join()
或detach()
,否则可能引发资源泄露。
注意点
std::thread
构造后即启动,不能"延迟启动"。join()
:主线程等待子线程执行完毕。detach()
:子线程后台运行,主线程不再关心其状态。- 未调用
join()
或detach()
就析构std::thread
,会导致程序崩溃。
2 状态转换
在 C/C++ 中,线程状态的转换并不像 Java 那样有统一的虚拟机控制模型,而是依赖于底层操作系统(如 Linux、Windows)调度机制。C++ 本身通过 std::thread
提供了对系统线程(如 POSIX Threads 或 Windows Threads)的封装,但不显式暴露线程状态。
结合操作系统线程模型,理解 C/C++ 中线程状态的转换路径。
2.1 C/C++ 线程状态转换图(基于 Linux/POSIX 和 std::thread
)
简单版本
text
[New]
↓
[Ready] ↔ [Running] → [Terminated]
↑ ↓
[Blocked] ←---
text
+--------+ thread constructor
| New | --------------------------+
+--------+ |
| v
| +-------------+
| OS调度 | Runnable |
+----------------------> +-------------+
| |
v |
+--------------+ | 被抢占或 yield
| Running | <----+
+--------------+
|
+----------------------+------------------------------+
| | |
v v v
[Waiting on lock] [Waiting on cond_var] [sleep_for / sleep_until]
Blocked Waiting (CondVar) Sleeping
+ + +
| | |
+---------> 信号/条件满足/定时器超时 <---------------+
|
v
+--------------+
| Runnable |
+--------------+
|
v
+--------------+
| Running |
+--------------+
|
执行结束 or 异常
|
v
+--------------+
| Terminated |
+--------------+
Linux 实际版
text
+-------------+
| Running | <--------+
+-------------+ |
| ^ |
preempt schedule |
v | |
+-------------+ |
| Runnable | ---------+
+-------------+
|
+------+------+
| |
+-------+ +--------+
| Sleep | | Disk |
| (S) | | Sleep |
+-------+ | (D) |
| +--------+
| |
v v
+---------------------+
| Runnable |
+---------------------+
(via wakeup or I/O completion)
2.2 状态转换说明
状态名称 | 触发条件 | 示例代码 |
---|---|---|
New → Runnable | 创建线程对象 std::thread t(...) |
std::thread t(myFunc); |
Runnable → Running | 被操作系统调度 | 自动完成,无需显式操作 |
Running → Blocked | 获取互斥锁失败(如 mutex.lock() ) |
std::unique_lock<std::mutex> lock(m); |
Running → Waiting | 调用 condition_variable.wait() |
cv.wait(lock); |
Running → Sleeping | 调用 std::this_thread::sleep_for(...) |
std::this_thread::sleep_for(1s); |
Blocked/Waiting/Sleeping → Runnable | 条件满足/超时/锁释放 | 由 OS 处理,代码中不可见 |
Running → Terminated | 线程函数返回/异常 | 函数结束或 return |
2.3 示例:多个状态的转换代码
cpp
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <chrono>
std::mutex mtx;
std::condition_variable cv;
bool ready = false;
void worker() {
std::unique_lock<std::mutex> lock(mtx);
std::cout << "Worker: waiting...\n";
// Running → Waiting(挂起等待条件变量)
cv.wait(lock, [] { return ready; });
std::cout << "Worker: resumed and working...\n";
// Running → Sleeping
std::this_thread::sleep_for(std::chrono::seconds(1));
std::cout << "Worker: finished.\n";
// → Terminated
}
int main() {
std::thread t(worker);
std::this_thread::sleep_for(std::chrono::seconds(2));
{
std::lock_guard<std::mutex> lock(mtx);
ready = true;
std::cout << "Main: notifying worker...\n";
}
cv.notify_one();
t.join();
}
执行结果
bash
Worker: waiting...
Main: notifying worker...
Worker: resumed and working...
Worker: finished.
3 调试
3.1 Linux 中线程/进程的典型状态码
运行命令如:
bash
ps -o pid,tid,stat,comm -L -p <pid>
或者使用 top
,会看到类似以下状态码:
例如输出:
PID TID STAT COMMAND
12345 12345 Ss my_program
12345 12346 Sl my_program
12345 12347 Rl my_program
12345 12348 S my_program
Ss
:主线程,sleeping 且为 session leader。Sl
:sleeping + 多线程(L)。Rl
:runnable + 多线程(L)。S
:普通 sleeping 线程。
状态码 | 含义 | 说明 |
---|---|---|
R |
Running / Runnable | 正在运行,或在运行队列中等待调度 |
S |
Sleeping (Interruptible) | 可中断的睡眠,等待事件或条件,如 sleep() 、read() |
D |
Uninterruptible sleep | 不可中断的睡眠(通常为 IO),如等待磁盘或网络 |
T |
Traced / Stopped | 被调试器暂停或收到 SIGSTOP 信号 |
Z |
Zombie | 僵尸进程,子进程已终止但父进程未调用 wait() |
X |
Dead | 非正常终止(很少见) |
3.2 深入 /proc/[pid]/task/
查看线程状态
Linux 把每个线程当作一个任务(task),在 /proc/[pid]/task/
下有所有线程的子目录:
bash
ls /proc/<pid>/task/
然后可以查看每个线程状态:
bash
cat /proc/<pid>/task/<tid>/status
输出中有一行:
State: S (sleeping)
其他可能值包括:
R (running)
D (disk sleep)
T (stopped)
Z (zombie)
3.3 状态之间的实际转换(C++ 映射)
Linux 状态 | 对应 C++ 场景 |
---|---|
R (Runnable) |
正在执行或准备被调度,CPU 调度队列中 |
S (Sleeping) |
std::this_thread::sleep_for 、等待条件变量、I/O 等 |
D (Disk Sleep) |
被阻塞在磁盘或网络 I/O(不可中断) |
T (Stopped) |
被调试或 SIGSTOP 暂停 |
Z (Zombie) |
线程/进程退出但未被 join() /wait() |
3.5 调试技巧
htop
可视化线程状态
bash
htop
# F2 -> Display options -> Show custom thread names (如你设置了)
gdb
附加调试线程状态
bash
gdb -p <pid>
info threads
perf top
查看哪些线程/函数在消耗 CPU
总结:线程状态的决定者是谁?
决定因素 | 状态 |
---|---|
程序员代码 | 睡眠、等待、join 等显式操作 |
操作系统调度器 | Running / Runnable 切换、抢占等 |
锁竞争 | Blocked(mutex、spinlock) |