- 操作系統:ubuntu22.04
- IDE:Visual Studio Code
- 編程語言:C++11
算法描述
std::thread 是 C++11 標準庫中用于創建和管理線程的核心類,定義在 頭文件中。它使得多線程編程變得簡單、類型安全且跨平臺。
一、std::thread 簡介
std::thread 是一個類,代表一個執行線程。你可以用它來啟動一個函數(普通函數、lambda、函數對象、成員函數等)在新的線程中運行。
🔧 所需頭文件:
#include <thread>
📦 常用成員函數:
函數 | 說明 |
---|---|
join() | 等待線程執行完畢(阻塞主線程) |
detach() | 分離線程,讓其在后臺獨立運行 |
get_id() | 獲取線程的唯一 ID |
joinable() | 判斷線程是否可以 join 或 detach |
swap() | 交換兩個 thread 對象 |
native_handle() | 獲取底層平臺的原生線程句柄(如 pthread_t) |
二、創建線程的多種方式(附示例)
- 使用普通函數
#include <iostream>
#include <thread>
#include <chrono>void hello()
{std::this_thread::sleep_for(std::chrono::milliseconds(100));std::cout << "Hello from thread " << std::this_thread::get_id() << std::endl;
}int main()
{std::thread t(hello); // 啟動線程執行 hello 函數std::cout << "Main thread ID: " << std::this_thread::get_id() << std::endl;t.join(); // 等待線程結束std::cout << "Thread joined." << std::endl;return 0;
}
輸出示例:
Main thread ID: 1
Hello from thread 2
Thread joined.
- 使用帶參數的函數
void print_message(const std::string& msg, int n)
{for (int i = 0; i < n; ++i) {std::cout << msg << std::endl;std::this_thread::sleep_for(std::chrono::milliseconds(50));}
}int main()
{std::thread t(print_message, "Hello from thread!", 3);std::cout << "Main thread is running..." << std::endl;t.join();std::cout << "Thread finished." << std::endl;return 0;
}
?? 注意:參數是值傳遞的。如果要傳引用,必須用 std::ref。
? 正確傳遞引用:
void increment(int& x)
{++x;
}int main()
{int a = 0;std::thread t(increment, std::ref(a)); // 使用 std::ref 傳引用t.join();std::cout << "a = " << a << std::endl; // 輸出: a = 1return 0;
}
? 3. 使用 Lambda 表達式
int main()
{int local = 10;std::thread t([local](){ // 捕獲 local 的副本std::cout << "Lambda: local = " << local << std::endl;std::this_thread::sleep_for(std::chrono::seconds(1));});t.join();return 0;
}
提示:如果要修改捕獲的變量,使用 mutable 或傳引用:
std::thread t([&local]() mutable
{local += 5;std::cout << "Modified: " << local << std::endl;
});
? 4. 使用函數對象(仿函數)
struct Task
{void operator()() const{std::cout << "Task executed in thread " << std::this_thread::get_id() << std::endl;}
};int main()
{std::thread t(Task{});t.join();return 0;
}
? 5. 使用類的成員函數
class Worker
{
public:void work(int id){std::cout << "Worker " << id << " working in thread " << std::this_thread::get_id() << std::endl;}
};int main()
{Worker w;std::thread t(&Worker::work, &w, 42); // &w 是對象指針,42 是參數t.join();return 0;
}
🔍 解釋:&Worker::work 是成員函數指針,&w 是對象地址,42 是參數。
三、join() vs detach()
? 每個 std::thread 對象在析構前必須被 join 或 detach,否則程序會 std::terminate()。
? join():等待線程結束
std::thread t(some_function);
t.join(); // 主線程阻塞,直到 t 結束
// 此時 t 不再可 join,t.joinable() 返回 false
? detach():分離線程
std::thread t(some_function);
t.detach(); // 線程在后臺運行,不再與 thread 對象關聯
// 不能再 join,線程生命周期由系統管理
?? 分離線程的風險:如果主線程結束,整個程序終止,分離線程也會被強制終止。
🧪 四、檢查線程狀態:joinable()
std::thread t(some_function);if (t.joinable())
{t.join(); // 安全調用
}
常用于異常安全代碼中,確保線程被正確處理。
🧰 五、線程 ID 與當前線程操作
#include <iostream>
#include <thread>void show_id()
{std::cout << "This thread ID: " << std::this_thread::get_id() << std::endl;
}int main()
{std::thread t(show_id);std::cout << "Main thread ID: " << std::this_thread::get_id() << std::endl;t.join();// 讓出 CPU 時間片std::this_thread::yield();// 休眠 500 毫秒std::this_thread::sleep_for(std::chrono::milliseconds(500));return 0;
}
🧱 六、線程安全與共享數據(簡單示例)
#include <iostream>
#include <thread>
#include <mutex>int counter = 0;
std::mutex mtx;void increment()
{for (int i = 0; i < 100000; ++i) {std::lock_guard<std::mutex> lock(mtx);++counter;}
}int main()
{std::thread t1(increment);std::thread t2(increment);t1.join();t2.join();std::cout << "Final counter: " << counter << std::endl; // 應為 200000return 0;
}
🔐 使用 std::mutex 和 std::lock_guard 保護共享變量 counter。
🚫 七、常見錯誤與注意事項
? 錯誤1:未調用 join 或 detach
int main()
{std::thread t([]{ std::cout << "Hello"; });return 0; // t 析構時未 join/detach → 調用 std::terminate()
}
? 正確做法:
std::thread t(...);
// ...
t.join(); // 或 t.detach();
? 錯誤2:傳遞指針或引用時對象已銷毀
std::thread t(increment, std::ref(local_var));
// 如果 local_var 是局部變量且線程未結束,可能訪問已銷毀內存
? 建議:確保線程使用的數據生命周期長于線程本身。
? 八、完整示例:多線程并行計算
#include <iostream>
#include <vector>
#include <thread>
#include <numeric>void accumulate(const std::vector<int>& vec, int start, int end, int& result){result = std::accumulate(vec.begin() + start, vec.begin() + end, 0);
}int main()
{std::vector<int> data(100000, 1); // 10萬個1int sum1 = 0, sum2 = 0;std::thread t1(accumulate, std::ref(data), 0, 50000, std::ref(sum1));std::thread t2(accumulate, std::ref(data), 50000, 100000, std::ref(sum2));t1.join();t2.join();std::cout << "Total sum: " << sum1 + sum2 << std::endl; // 100000return 0;
}
總結:std::thread 核心要點
要點 | 說明 |
---|---|
? 啟動線程 | std::thread t(func, args…) |
? 等待結束 | t.join() |
? 后臺運行 | t.detach() |
? 安全檢查 | t.joinable() |
? 線程ID | t.get_id() 或 std::this_thread::get_id() |
? 傳引用 | 使用 std::ref() |
? 異常安全 | 在異常路徑中也要 join/detach |
掌握 std::thread 是學習 C++ 多線程的第一步。結合 mutex、condition_variable 和 future,你就能構建出高效、安全的并發程序。建議多寫小例子練習傳參、生命周期管理、同步等關鍵點。