接上篇,詳細講解 std::thread 的構造、同步、異常處理及後台運行模式。
void do_work(); // 普通函數
std::thread t1(do_work);
struct Task { void operator()() { /*...*/ } }; // 仿函數
std::thread t2(Task()); // 注意:最 vexing parse!應寫
std::thread t2((Task())); // 或 C++11 統一初始化
std::thread t2{Task()};
auto lambda = []{ /*...*/ };
std::thread t3(lambda);
關鍵點:std::thread t(Task()) 被解析為函數聲明,需加額外括號或用花括號初始化。
join():阻塞當前線程,直到目標線程結束。只能調用一次,之後 joinable() == false。detach():線程獨立運行,不再與 thread 對象關聯。主線程結束不等待它,但需確保線程不訪問已銷毀的局部變量。void oops() {
int local = 0;
std::thread t([&]{ for(int i=0;i<1e6;++i) ++local; });
t.detach(); // 危險!t 可能訪問已銷毀的 local
}
若主線程拋出異常未捕獲,detach 線程可能訪問無效內存;join 未調用則資源洩漏。兩種模式:
// 模式一:try-catch
std::thread t(func);
try {
do_other_work();
} catch (...) {
if (t.joinable()) t.join();
throw;
}
// 模式二:RAII 守衛(推薦)
class thread_guard {
std::thread& t;
public:
explicit thread_guard(std::thread& t_) : t(t_) {}
~thread_guard() { if (t.joinable()) t.join(); }
thread_guard(const thread_guard&) = delete;
thread_guard& operator=(const thread_guard&) = delete;
};
void safe() {
std::thread t(func);
thread_guard g(t);
do_other_work(); // 異常拋出時 g 析構自動 join
}
適用於無需等待、獨立任務(如 Word 多文檔編輯)。調用 detach() 後,線程生命週期由運行時管理。需保證線程不依賴主線程棧上變量,通常傳遞共享指針或複製數據。
join(),配合 RAII 守衛確保異常安全。detach() 仅用於真正獨立、無共享棧變量的後台任務。