Linux 線程模型經歷從 LinuxThreads 到 NPTL (Native POSIX Thread Library) 的演進。本文深入分析進程與線程關係、核心輕量進程實現、線程模型分類 (1:1、M:N、M:1)、LinuxThreads 架構與 NPTL 改進。
| 模型 | 用戶線程:核心線程 | 調度者 | 優點 | 缺點 | 代表 |
| M:1 (用戶級) | 多對一 | 用戶態程式庫 | 切換極快、無核心支援需求 | 無法利用多核、阻塞系統呼叫會卡住所有線程 | 早期 Green Threads |
| 1:1 (核心級) | 一對一 | 核心排程器 | 真正並行、阻塞不影響其他線程 | 建立/切換開銷大、受限於核心 PID 上限 | LinuxThreads, NPTL, Windows |
| M:N (混合型) | 多對多 | 雙層調度 | 兼顧並行與效率、靈活 | 實現極其複雜、優先權反轉難題 | Solaris, FreeBSD 早期, IRIX |
三、Linux 核心輕量進程實現
Linux 核心不區分「進程」與「線程」,統一視為 任務,透過 clone() 系統呼叫以旗標控制資源共享程度:
// include/linux/sched.h
#define CLONE_VM 0x00000100 // 共享記憶體空間
#define CLONE_FS 0x00000200 // 共享檔案系統資訊
#define CLONE_FILES 0x00000400 // 共享開啟檔案表
#define CLONE_SIGHAND 0x00000800 // 共享信號處理器
#define CLONE_THREAD 0x00010000 // 同線程群組 (共享 PID、信號)
#define CLONE_PARENT 0x00008000 // 共享父進程
fork() 相當於 clone(SIGCHLD) — 複製所有資源
pthread_create() 相當於 clone(CLONE_VM|CLONE_FS|CLONE_FILES|CLONE_SIGHAND|CLONE_THREAD) — 幾乎完全共享
- 核心內部
do_fork() 統一處理上述所有變體
四、LinuxThreads (舊實現,已棄用)
- 採用 1:1 模型,每條線程對應一個核心任務
- 用戶態程式庫 (
libpthread) 實作:線程管理、信號處理、同步原語 (mutex、cond、rwlock)
- 管理線程 (manager thread) 處理線程建立/銷毀、信號分發
- 缺陷: 信號處理不符 POSIX、
getpid() 回傳線程 ID 而非進程 ID、setuid() 不影響所有線程、效能較差
五、NPTL (Native POSIX Thread Library) - 現代標準
- 同為 1:1 模型,但核心與用戶態深度協作
- 核心改進 (2.6+):
- 線程群組 ID (TGID) 概念:
getpid() 回傳 TGID,gettid() 回傳核心線程 ID
- futex (Fast Userspace Mutex) — 高效用戶態鎖,核心僅介入競爭情況
- 健全的信號處理:
pthread_kill()、sigwait() 等完整支援
setuid()/setgid() 影響整個線程群組
- O(1) 排程器 → CFS 完全公平排程器
- 用戶態改進 (glibc):
- 無管理線程,直接用
clone() 建立線程
- TLS (Thread Local Storage) 高效實現
- 優化的同步原語 (pthread_mutex_t 等)
- 支援
pthread_atfork()、健全的取消機制
六、關鍵資料結構
// 核心任務描述符 (include/linux/sched.h)
struct task_struct {
pid_t pid; // 線程 ID (TID)
pid_t tgid; // 線程群組 ID (PID)
struct mm_struct *mm; // 記憶體描述符 (共享則指向同一個)
struct files_struct *files; // 檔案描述子表 (共享則指向同一個)
struct signal_struct *signal; // 信號處理 (共享則指向同一個)
// ... 較多欄位
};
// 用戶態 pthread 內部結構 (glibc/nptl/descr.h)
struct pthread {
pid_t tid; // 核心線程 ID
pid_t pid; // 進程 ID (TGID)
void *stackaddr; // 堆疊基址
size_t stacksize; // 堆疊大小
// ... 同步鎖、TLS、取消狀態等
};
七、效能特徵與調優建議
| 指標 | 數值/建議 |
| 線程建立開銷 | ~1-5 微秒 (含堆疊分配、clone 系統呼叫) |
| 上下文切換 | ~0.5-2 微秒 (同進程內線程切換更快,共享 TLB/mm) |
| 預設堆疊大小 | 8 MiB (可透過 pthread_attr_setstacksize() 調整,最小 ~2 MiB) |
| 最大線程數 | 受限於 /proc/sys/kernel/pid_max (預設 32768) 與虛擬記憶體 |
| 調優建議 | 使用線程池避免頻繁建銷毀、適當減小堆疊、避免過度鎖競爭、善用無鎖資料結構 |
八、除錯與觀測工具
# 查看進程所有線程
ps -eLf
top -H -p
# 追蹤系統呼叫
strace -f -p
# 核心線程資訊
cat /proc//task//status
# 性能分析
perf record -g -p
perf report