文章目錄
- 線程狀態以及轉換
- 1 基本狀態
- 1.1 新建(New)
- 1.2 就緒(Ready / Runnable)
- 1.3 運行中(Running)
- 1.4 阻塞/等待(Blocked / Waiting / Sleeping)
- 1.5 掛起(Suspended)
- 1.6 終止(Terminated / Dead / Exit)
- 注意點
- 2 狀態轉換
- 2.1 C/C++ 線程狀態轉換圖(基于 Linux/POSIX 和 `std::thread`)
- 2.2 狀態轉換說明
- 2.3 示例:多個狀態的轉換代碼
- 3 調試
- 3.1 Linux 中線程/進程的典型狀態碼
- 3.2 深入 `/proc/[pid]/task/` 查看線程狀態
- 3.3 狀態之間的實際轉換(C++ 映射)
- 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
)
簡單版本
[New] ↓[Ready] ? [Running] → [Terminated]↑ ↓[Blocked] ←---
+--------+ 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 實際版
+-------------+| 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 示例:多個狀態的轉換代碼
#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 → Sleepingstd::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();
}
執行結果
Worker: waiting...
Main: notifying worker...
Worker: resumed and working...
Worker: finished.
3 調試
3.1 Linux 中線程/進程的典型狀態碼
運行命令如:
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/
下有所有線程的子目錄:
ls /proc/<pid>/task/
然后可以查看每個線程狀態:
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
可視化線程狀態
htop
# F2 -> Display options -> Show custom thread names (如你設置了)
gdb
附加調試線程狀態
gdb -p <pid>
info threads
perf top
查看哪些線程/函數在消耗 CPU
總結:線程狀態的決定者是誰?
決定因素 | 狀態 |
---|---|
程序員代碼 | 睡眠、等待、join 等顯式操作 |
操作系統調度器 | Running / Runnable 切換、搶占等 |
鎖競爭 | Blocked(mutex、spinlock) |