目錄
1. std::thread與pthread對比
std::thread是C++11接口,使用時需要包含頭文件#include <thread>,編譯時需要支持c++11標准。thread中封裝了pthread的方法,所以也需要鏈接pthread庫
pthread是C++98接口且只支持Linux,使用時需要包含頭文件#include <pthread.h>,編譯時需要鏈接pthread庫
std::thread對比於pthread的優缺點:
優點:
1. 簡單,易用
2. 跨平台,pthread只能用在POSIX系統上(其他系統有其獨立的thread實現)
3. 提供了更多高級功能,比如future
4. 更加C++(跟匿名函數,std::bind,RAII等C++特性更好的集成)
缺點:
1. 沒有RWlock。有一個類似的shared_mutex,不過它屬於C++14,你的編譯器很有可能不支持。
2. 操作線程和Mutex等的API較少。畢竟為了跨平台,只能選取各原生實現的子集。如果你需要設置某些屬性,需要通過API調用返回原生平台上的對應對象,再對返回的對象進行操作。
2. std::thread簡介
2.1 std::thread構造函數
默認構造函數,創建一個空的 std::thread 執行對象。
初始化構造函數,創建一個 std::thread 對象,該 std::thread 對象可被 joinable,新產生的線程會調用 fn 函數,該函數的參數由 args 給出。
拷貝構造函數(被禁用),意味着 std::thread 對象不可拷貝構造。
Move 構造函數,move 構造函數(move 語義是 C++11 新出現的概念,詳見附錄),調用成功之后 x 不代表任何 std::thread 執行對象。
注意:可被 joinable 的 std::thread 對象必須在他們銷毀之前被主線程 join 或者將其設置為 detached.
實例
#include <iostream>
#include <utility>
#include <thread>
#include <chrono>
#include <functional>
#include <atomic>
void f1(int n)
{
for (int i = 0; i < 5; ++i) {
std::cout << "Thread " << n << " executing\n";
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
}
void f2(int& n)
{
for (int i = 0; i < 5; ++i) {
std::cout << "Thread 2 executing\n";
++n;
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
}
int main()
{
int n = 0;
std::thread t1; // t1 is not a thread
std::thread t2(f1, n + 1); // pass by value
std::thread t3(f2, std::ref(n)); // pass by reference
std::thread t4(std::move(t3)); // t4 is now running f2(). t3 is no longer a thread
t2.join();
t4.join();
std::cout << "Final value of n is " << n << '\n';
}
// 編譯: g++ -g test.cpp -o test -std=c++11 -lpthread
/*結果:
Thread 1 executing
Thread 2 executing
Thread 1 executing
Thread 2 executing
Thread 1 executing
Thread 2 executing
Thread 1 executing
Thread 2 executing
Thread 1 executing
Thread 2 executing
Final value of n is 5
*/
2.2 std::thread其他函數
get_id: 獲取線程 ID,返回一個類型為 std::thread::id 的對象。
joinable: 檢查線程是否可被 join。檢查當前的線程對象是否表示了一個活動的執行線程,由默認構造函數創建的線程是不能被 join 的。另外,如果某個線程 已經執行完任務,但是沒有被 join 的話,該線程依然會被認為是一個活動的執行線程,因此也是可以被 join 的。
detach: Detach 線程。 將當前線程對象所代表的執行實例與該線程對象分離,使得線程的執行可以單獨進行。一旦線程執行完畢,它所分配的資源將會被釋放。
swap: Swap 線程,交換兩個線程對象所代表的底層句柄(underlying handles)。
native_handle: 返回 native handle(由於 std::thread 的實現和操作系統相關,因此該函數返回與 std::thread 具體實現相關的線程句柄,例如在符合 Posix 標准的平台下(如 Unix/Linux)是 Pthread 庫)。
hardware_concurrency [static]: 檢測硬件並發特性,返回當前平台的線程實現所支持的線程並發數目,但返回值僅僅只作為系統提示(hint)。
實例:
#include <iostream>
#include <thread>
#include <chrono>
void foo()
{
std::this_thread::sleep_for(std::chrono::seconds(1));
}
void bar()
{
std::this_thread::sleep_for(std::chrono::seconds(1));
}
void independentThread()
{
std::cout << "Starting concurrent thread." << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(2));
std::cout << "Exiting concurrent thread." << std::endl;
}
int main()
{
/*************** 1. get_id()實例 *********************/
std::thread t1(foo);
std::thread::id t1_id = t1.get_id();
std::thread t2(foo);
std::thread::id t2_id = t2.get_id();
std::cout << "t1's id: " << t1_id << std::endl;
std::cout << "t2's id: " << t2_id << std::endl;
t1.join();
t2.join();
/*輸出
t1's id: 140097921648384
t2's id: 140097913255680
*/
/*************** 2. joinable()/join()實例 *********************/
std::thread t;
std::cout << "before starting, joinable: " << t.joinable() << std::endl;
t = std::thread(foo);
std::cout << "after starting, joinable: " << t.joinable() << std::endl;
// Join 線程,調用該函數會阻塞當前線程,直到由 *this 所標示的線程執行完畢 join 才返回。
t.join();
/*輸出
before starting, joinable: 0
after starting, joinable: 1
*/
/*************** 3. detach()實例 *********************/
std::thread t3(independentThread);
t3.detach();
std::this_thread::sleep_for(std::chrono::seconds(5));
/*輸出。PS:如果不加上面這一行,會出現t3還沒完成,主線程就結束了
Starting concurrent thread.
Exiting concurrent thread.
*/
/*************** 4. swap實例 *********************/
std::thread t4(foo);
std::thread t5(bar);
std::cout << "thread 4 id: " << t4.get_id() << std::endl;
std::cout << "thread 5 id: " << t5.get_id() << std::endl;
std::swap(t4, t5);
std::cout << "after std::swap(t4, t5):" << std::endl;
std::cout << "thread 4 id: " << t4.get_id() << std::endl;
std::cout << "thread 5 id: " << t5.get_id() << std::endl;
t4.swap(t5);
std::cout << "after t4.swap(t5):" << std::endl;
std::cout << "thread 4 id: " << t4.get_id() << std::endl;
std::cout << "thread 5 id: " << t5.get_id() << std::endl;
t4.join();
t5.join();
/*輸出
thread 4 id: 139705731315456
thread 5 id: 139705739708160
after std::swap(t4, t5):
thread 4 id: 139705739708160
thread 5 id: 139705731315456
after t4.swap(t5):
thread 4 id: 139705731315456
thread 5 id: 139705739708160
*/
return 0;
}
// g++ -g test.cpp -o test -std=c++11 -lpthread
2.3 std::this_thread 命名空間中相關輔助函數介紹
get_id: 獲取線程 ID。
yield: 當前線程放棄執行,操作系統調度另一線程繼續執行。
sleep_until: 線程休眠至某個指定的時刻(time point),該線程才被重新喚醒。
sleep_for: 線程休眠某個指定的時間片(time span),該線程才被重新喚醒,不過由於線程調度等原因,實際休眠時間可能比 sleep_duration 所表示的時間片更長。
實例
#include <iostream>
#include <thread>
#include <chrono>
#include <mutex>
std::mutex g_display_mutex;
void foo()
{
std::thread::id this_id = std::this_thread::get_id();
g_display_mutex.lock();
std::cout << "thread " << this_id << " sleeping..." << std::endl;
g_display_mutex.unlock();
std::this_thread::sleep_for(std::chrono::seconds(1));
}
// "busy sleep" while suggesting that other threads run
// for a small amount of time
void little_sleep(std::chrono::microseconds us)
{
auto start = std::chrono::high_resolution_clock::now();
auto end = start + us;
do {
std::this_thread::yield();
} while (std::chrono::high_resolution_clock::now() < end);
}
int main()
{
/********************* 1. std::this_thread::get_id()實例 *********************/
std::thread t1(foo);
std::thread t2(foo);
t1.join();
t2.join();
/*結果:
thread 140251680864000 sleeping...
thread 140251672471296 sleeping...
*/
/********************* 2. std::this_thread::yield()實例 *********************/
auto start = std::chrono::high_resolution_clock::now();
little_sleep(std::chrono::microseconds(100));
auto elapsed = std::chrono::high_resolution_clock::now() - start;
std::cout << "waited for "
<< std::chrono::duration_cast<std::chrono::microseconds>(elapsed).count()
<< " microseconds" << std::endl;
/*結果:
waited for 102 microseconds
*/
/********************* 3. std::this_thread::sleep_for實例 *********************/
std::cout << "Hello waiter" << std::endl;
std::chrono::milliseconds dura( 2000 );
std::this_thread::sleep_for( dura );
std::cout << "Waited 2000 ms" << std::endl;
/*結果:
Hello waiter
Waited 2000 ms
*/
return 0;
}
// g++ -g test.cpp -o test -std=c++11 -lpthread
3. pthread簡介
pthread_create 創建線程
pthread_exit 終止線程
pthread_join 連接線程
pthread_detach 分離線程
https://www.runoob.com/w3cnote/cpp-std-thread.html
https://www.runoob.com/cplusplus/cpp-multithreading.html