C++中的std::thread
是C++11引入的線程庫的一部分,提供了創建和管理線程的能力。它封裝了操作系統的線程接口,使得在C++中更方便地進行多線程編程。
1. std::thread
的定義
std::thread
類位于<thread>
頭文件中,定義在std
命名空間下,用于表示一個獨立執行的線程對象。其基本聲明如下:
#include <thread>
std::thread 可以傳遞各種類型的參數,但要注意:
默認按值傳遞,如果要傳引用,用 std::ref(x)。
移動對象用 std::move,避免不必要的拷貝。
成員函數必須傳對象指針(&obj)。
2. std::thread
的構造函數
std::thread
提供了多個構造函數,允許不同方式創建線程。
(1) 默認構造函數
std::thread();
- 創建一個空的
std::thread
對象,不與任何可執行線程關聯。
#include <iostream>
#include <thread>int main() {std::thread t; // 默認構造,不與任何線程關聯std::cout << "t is joinable? " << t.joinable() << std::endl; // 輸出 0(false)return 0;
}
(2) 可調用對象構造
template< class Function, class... Args >
explicit thread(Function&& f, Args&&... args);
- 傳入一個可調用對象(函數、函數對象、lambda 等)和參數,創建一個新的線程。
#include <iostream>
#include <thread>void func(int x) {std::cout << "Thread function with arg: " << x << std::endl;
}int main() {std::thread t(func, 10); // 創建線程并執行 func(10)t.join(); // 等待線程執行完畢return 0;
}
(3) 移動構造函數
thread(thread&& other) noexcept;
std::thread
是不可拷貝的,但可以移動。- 該構造函數接收另一個
std::thread
對象,并接管其線程。
#include <iostream>
#include <thread>void func() {std::cout << "Thread running\n";
}int main() {std::thread t1(func);std::thread t2 = std::move(t1); // t1移動到t2,t1不再管理線程t2.join();return 0;
}
(4) 拷貝構造(刪除)
thread(const thread&) = delete;
std::thread
對象不能被拷貝,因為線程的所有權是唯一的。- 這樣設計是為了避免多個
std::thread
對象管理同一個線程,導致未定義行為。
#include <thread>void func() {}int main() {std::thread t1(func);// std::thread t2 = t1; // ? 錯誤,不能拷貝return 0;
}
3. std::thread
的常用成員函數
(1) join()
- 等待線程結束
void join();
- 阻塞調用線程,直到目標線程執行完畢。
- 必須在可聯結的線程上調用,否則會導致異常。
#include <iostream>
#include <thread>void func() {std::cout << "Thread running\n";
}int main() {std::thread t(func);t.join(); // 等待線程執行完畢return 0;
}
(2) detach()
- 分離線程
void detach();
- 讓線程在后臺運行,與
std::thread
對象分離。 - 線程對象會立即銷毀,但線程繼續執行,執行完畢后自動釋放資源。
#include <iostream>
#include <thread>
#include <chrono>void func() {std::this_thread::sleep_for(std::chrono::seconds(2));std::cout << "Thread finished\n";
}int main() {std::thread t(func);t.detach(); // 線程進入后臺std::cout << "Main thread continues...\n";std::this_thread::sleep_for(std::chrono::seconds(3)); // 主線程等待return 0;
}
注意:如果主線程退出而分離線程還未執行完,可能會導致未定義行為。因此應謹慎使用detach()
。
(3) joinable()
- 判斷線程是否可聯結
bool joinable() const noexcept;
- 如果線程對象管理一個有效線程,則返回
true
。
std::thread t(func);
if (t.joinable()) {t.join();
}
(4) get_id()
- 獲取線程ID
std::thread::id get_id() const noexcept;
- 獲取線程的唯一ID。
#include <iostream>
#include <thread>void func() {std::cout << "Thread ID: " << std::this_thread::get_id() << std::endl;
}int main() {std::thread t(func);t.join();return 0;
}
(5) native_handle()
- 獲取操作系統的線程句柄
native_handle_type native_handle();
- 獲取線程的原生句柄,可用于底層線程操作(如設置優先級等)。
(6) hardware_concurrency()
- 獲取硬件支持的線程數
static unsigned int hardware_concurrency() noexcept;
- 返回系統建議的并發線程數。
#include <iostream>
#include <thread>int main() {std::cout << "Hardware concurrency: " << std::thread::hardware_concurrency() << std::endl;return 0;
}
4. std::thread
的用法示例
(1) 使用Lambda表達式
#include <iostream>
#include <thread>int main() {std::thread t([] {std::cout << "Lambda thread running\n";});t.join();return 0;
}
(2) 線程數組
#include <iostream>
#include <thread>
#include <vector>void func(int i) {std::cout << "Thread " << i << " started\n";
}int main() {std::vector<std::thread> threads;for (int i = 0; i < 5; ++i) {threads.emplace_back(func, i);}for (auto& t : threads) {t.join();}return 0;
}
總結
std::thread
不能拷貝,但可以移動。- 使用
join()
等待線程結束,使用detach()
分離線程。 - 使用
joinable()
檢查線程是否可聯結。 - 使用
get_id()
獲取線程ID。 hardware_concurrency()
獲取系統支持的線程數。
多線程編程需要注意數據同步,否則可能導致數據競爭(race condition)等問題。可以使用std::mutex
、std::condition_variable
等同步機制來解決這些問題。