C++11併發之std::thread
1、成員型別和成員函式。 2、std::thread 建構函式。 3、非同步。 4、多執行緒傳遞引數。 5、join、detach。 6、獲取CPU核心個數。 7、CPP原子變數與執行緒安全。 8、lambda與多執行緒。 9、時間等待相關問題。 10、執行緒功能拓展。 11、多執行緒可變引數。 12、執行緒交換。 13、執行緒移動。 std::thread 在 #include<thread> 標頭檔案中宣告,因此使用 std::thread 時需要包含 #include<thread>標頭檔案。
- id
- Thread id (public member type ) id
- Native handle type (public member type )
成員函式:
- Construct thread (public member function ) 建構函式
- Thread destructor (public member function ) 解構函式
-
Move-assign thread (public member function ) 賦值過載
- Get thread id (public member function ) 獲取執行緒id
- Check if joinable (public member function ) 判斷執行緒是否可以加入等待
- join
- Join thread (public member function ) 加入等待
- Detach thread (public member function ) 分離執行緒
- swap
-
Swap threads (public member function ) 執行緒交換
- Get native handle (public member function ) 獲取執行緒控制代碼
- Detect hardware concurrency (public static member function ) 檢測硬體併發特性
Non-member overloads:
- Swap threads (function )
- default (1)
-
thread() noexcept;
- initialization(2)
- template <class Fn, class... Args> explicit thread (Fn&& fn, Args&&... args);
- copy [deleted] (3)
-
thread (const thread&) = delete;
- move [4]
-
hread (thread&& x) noexcept;
(2).初始化建構函式,建立一個 thread 物件,該 thread 物件可被 joinable,新產生的執行緒會呼叫 fn 函式,該函式的引數由 args 給出。 (3).拷貝建構函式(被禁用),意味著 thread 不可被拷貝構造。 (4).move 建構函式,move 建構函式,呼叫成功之後 x 不代表任何 thread 執行物件。 注意:可被 joinable 的 thread 物件必須在他們銷燬之前被主執行緒 join 或者將其設定為 detached。 std::thread 各種建構函式例子如下:
<span style="font-size:12px;">#include<iostream>
#include<thread>
#include<chrono>
using namespace std;
void fun1(int n) //初始化建構函式
{
cout << "Thread " << n << " executing\n";
n += 10;
this_thread::sleep_for(chrono::milliseconds(10));
}
void fun2(int & n) //拷貝建構函式
{
cout << "Thread " << n << " executing\n";
n += 20;
this_thread::sleep_for(chrono::milliseconds(10));
}
int main()
{
int n = 0;
thread t1; //t1不是一個thread
thread t2(fun1, n + 1); //按照值傳遞
t2.join();
cout << "n=" << n << '\n';
n = 10;
thread t3(fun2, ref(n)); //引用
thread t4(move(t3)); //t4執行t3,t3不是thread
t4.join();
cout << "n=" << n << '\n';
return 0;
}
執行結果:
Thread 1 executing
n=0
Thread 10 executing
n=30</span>
3、非同步。
例如:
<span style="font-size:12px;">#include<iostream>
#include<thread>
using namespace std;
void show()
{
cout << "hello cplusplus!" << endl;
}
int main()
{
//棧上
thread t1(show); //根據函式初始化執行
thread t2(show);
thread t3(show);
//執行緒陣列
thread th[3]{thread(show), thread(show), thread(show)};
//堆上
thread *pt1(new thread(show));
thread *pt2(new thread(show));
thread *pt3(new thread(show));
//執行緒指標陣列
thread *pth(new thread[3]{thread(show), thread(show), thread(show)});
return 0;
}</span>
4、多執行緒傳遞引數。
例如:
<span style="font-size:12px;">#include<iostream>
#include<thread>
using namespace std;
void show(const char *str, const int id)
{
cout << "執行緒 " << id + 1 << " :" << str << endl;
}
int main()
{
thread t1(show, "hello cplusplus!", 0);
thread t2(show, "你好,C++!", 1);
thread t3(show, "hello!", 2);
return 0;
}
執行結果:
執行緒 1執行緒 2 :你好,C++!執行緒 3 :hello!
:hello cplusplus!</span>
發現,執行緒 t1、t2、t3 都執行成功!
5、join、detach。
join例子如下:
<span style="font-size:12px;">#include<iostream>
#include<thread>
#include<array>
using namespace std;
void show()
{
cout << "hello cplusplus!" << endl;
}
int main()
{
array<thread, 3> threads = { thread(show), thread(show), thread(show) };
for (int i = 0; i < 3; i++)
{
cout << threads[i].joinable() << endl;//判斷執行緒是否可以join
threads[i].join();//主執行緒等待當前執行緒執行完成再退出
}
return 0;
}
執行結果:
hello cplusplus!
hello cplusplus!
1
hello cplusplus!
1
1</span>
總結:
join 是讓當前主執行緒等待所有的子執行緒執行完,才能退出。
detach例子如下:
<span style="font-size:12px;">#include<iostream>
#include<thread>
using namespace std;
void show()
{
cout << "hello cplusplus!" << endl;
}
int main()
{
thread th(show);
//th.join();
th.detach();//脫離主執行緒的繫結,主執行緒掛了,子執行緒不報錯,子執行緒執行完自動退出。
//detach以後,子執行緒會成為孤兒執行緒,執行緒之間將無法通訊。
cout << th.joinable() << endl;
return 0;
}
執行結果:
hello cplusplus!
0</span>
結論:
執行緒 detach 脫離主執行緒的繫結,主執行緒掛了,子執行緒不報錯,子執行緒執行完自動退出。
執行緒 detach以後,子執行緒會成為孤兒執行緒,執行緒之間將無法通訊。
6、獲取CPU核心個數。
例如:
<span style="font-size:12px;">#include<iostream>
#include<thread>
using namespace std;
int main()
{
auto n = thread::hardware_concurrency();//獲取cpu核心個數
cout << n << endl;
return 0;
}
執行結果:
8</span>
結論:
通過 thread::hardware_concurrency() 獲取 CPU 核心的個數。
7、CPP原子變數與執行緒安全。
問題例如:
<span style="font-size:12px;">#include<iostream>
#include<thread>
using namespace std;
const int N = 100000000;
int num = 0;
void run()
{
for (int i = 0; i < N; i++)
{
num++;
}
}
int main()
{
clock_t start = clock();
thread t1(run);
thread t2(run);
t1.join();
t2.join();
clock_t end = clock();
cout << "num=" << num << ",用時 " << end - start << " ms" << endl;
return 0;
}
執行結果:
num=143653419,用時 730 ms</span>
從上述程式碼執行的結果,發現結果並不是我們預計的200000000,這是由於執行緒之間發生衝突,從而導致結果不正確。
為了解決此問題,有以下方法:
(1)互斥量。
例如:
<span style="font-size:12px;">#include<iostream>
#include<thread>
#include<mutex>
using namespace std;
const int N = 100000000;
int num(0);
mutex m;
void run()
{
for (int i = 0; i < N; i++)
{
m.lock();
num++;
m.unlock();
}
}
int main()
{
clock_t start = clock();
thread t1(run);
thread t2(run);
t1.join();
t2.join();
clock_t end = clock();
cout << "num=" << num << ",用時 " << end - start << " ms" << endl;
return 0;
}
執行結果:
num=200000000,用時 128323 ms</span>
不難發現,通過互斥量後運算結果正確,但是計算速度很慢,原因主要是互斥量加解鎖需要時間。
(2)原子變數。
例如:
<span style="font-size:12px;">#include<iostream>
#include<thread>
#include<atomic>
using namespace std;
const int N = 100000000;
atomic_int num{ 0 };//不會發生執行緒衝突,執行緒安全
void run()
{
for (int i = 0; i < N; i++)
{
num++;
}
}
int main()
{
clock_t start = clock();
thread t1(run);
thread t2(run);
t1.join();
t2.join();
clock_t end = clock();
cout << "num=" << num << ",用時 " << end - start << " ms" << endl;
return 0;
}
執行結果:
num=200000000,用時 29732 ms</span>
不難發現,通過原子變數後運算結果正確,計算速度一般。原子變數詳細內容 請參考C++11 併發之std::atomic。
(3)加入 join 。 例如:
<span style="font-size:12px;">#include<iostream>
#include<thread>
using namespace std;
const int N = 100000000;
int num = 0;
void run()
{
for (int i = 0; i < N; i++)
{
num++;
}
}
int main()
{
clock_t start = clock();
thread t1(run);
t1.join();
thread t2(run);
t2.join();
clock_t end = clock();
cout << "num=" << num << ",用時 " << end - start << " ms" << endl;
return 0;
}
執行結果:
num=200000000,用時 626 ms</span>
不難發現,通過原子變數後運算結果正確,計算速度也很理想。8、lambda與多執行緒。 例如:
<span style="font-size:12px;">#include<iostream>
#include<thread>
using namespace std;
int main()
{
auto fun = [](const char *str) {cout << str << endl; };
thread t1(fun, "hello world!");
thread t2(fun, "hello beijing!");
return 0;
}
執行結果:
hello world!
hello beijing!</span>
9、時間等待相關問題。
例如:
<span style="font-size:12px;">#include<iostream>
#include<thread>
#include<chrono>
using namespace std;
int main()
{
thread th1([]()
{
//讓執行緒等待3秒
this_thread::sleep_for(chrono::seconds(3));
//讓cpu執行其他空閒的執行緒
this_thread::yield();
//執行緒id
cout << this_thread::get_id() << endl;
});
return 0;
}</span>
10、執行緒功能拓展。
例如:
<span style="font-size:12px;">#include<iostream>
#include<thread>
using namespace std;
class MyThread :public thread //繼承thread
{
public:
//子類MyThread()繼承thread()的建構函式
MyThread() : thread()
{
}
//MyThread()初始化建構函式
template<typename T, typename...Args>
MyThread(T&&func, Args&&...args) : thread(forward<T>(func), forward<Args>(args)...)
{
}
void showcmd(const char *str) //執行system
{
system(str);
}
};
int main()
{
MyThread th1([]()
{
cout << "hello" << endl;
});
th1.showcmd("calc"); //執行calc
//lambda
MyThread th2([](const char * str)
{
cout << "hello" << str << endl;
}, " this is MyThread");
th2.showcmd("notepad");//執行notepad
return 0;
}
執行結果:
hello
//執行calc
hello this is MyThread
//執行notepad</span>
11、多執行緒可變引數。
例如:
<span style="font-size:12px;">#include<iostream>
#include<thread>
#include<cstdarg>
using namespace std;
int show(const char *fun, ...)
{
va_list ap;//指標
va_start(ap, fun);//開始
vprintf(fun, ap);//呼叫
va_end(ap);
return 0;
}
int main()
{
thread t1(show, "%s %d %c %f", "hello world!", 100, 'A', 3.14159);
return 0;
}
執行結果:
hello world! 100 A 3.14159</span>
12、執行緒交換。
例如:
<span style="font-size:12px;">#include<iostream>
#include<thread>
using namespace std;
int main()
{
thread t1([]()
{
cout << "thread1" << endl;
});
thread t2([]()
{
cout << "thread2" << endl;
});
cout << "thread1' id is " << t1.get_id() << endl;
cout << "thread2' id is " << t2.get_id() << endl;
cout << "swap after:" << endl;
swap(t1, t2);//執行緒交換
cout << "thread1' id is " << t1.get_id() << endl;
cout << "thread2' id is " << t2.get_id() << endl;
return 0;
}
執行結果:
thread1
thread2
thread1' id is 4836
thread2' id is 4724
swap after:
thread1' id is 4724
thread2' id is 4836</span>
兩個執行緒通過 swap 進行交換。
13、執行緒移動。
例如:
<span style="font-size:12px;">#include<iostream>
#include<thread>
using namespace std;
int main()
{
thread t1([]()
{
cout << "thread1" << endl;
});
cout << "thread1' id is " << t1.get_id() << endl;
thread t2 = move(t1);;
cout << "thread2' id is " << t2.get_id() << endl;
return 0;
}
執行結果:
thread1
thread1' id is 5620
thread2' id is 5620</span>
從上述程式碼中,執行緒t2可以通過 move 移動 t1 來獲取 t1 的全部屬性,而 t1 卻銷燬了。
相關推薦
C++11併發之std::thread
知識連結: C++11 併發之std::atomic 本文概要: 1、成員型別和成員函式。 2、std::thread 建構函式。 3、非同步。 4、多執行緒傳遞引數。 5、join、deta
c++11特性之std::thread--初識二
上篇部落格《c++11特性之std::thread–初識》初步介紹了std::thread,並且介紹了幾個成員函式。 最後的一段程式碼留了點懸念,就是vs2015會報錯,錯誤如下: error
c++11特性之std::thread--初識
C++11中已經擁有了一個更好用的用於執行緒操作的類std::thread。 預設建構函式: thread() noexcept; 構造一個任何執行緒不執行的執行緒物件。 初始化函式: template <class Fn, class...
[cpp].c++11學習筆記-std thread
std::thread用於啟動執行緒,可以用作跨平臺的執行緒庫。 它啟動執行緒的方式很靈活,可以支援C函式,類成員函式,類靜態函式等。 #include <thread> //標頭檔
C++11 併發指南二(std::thread 詳解)
上一篇部落格《C++11 併發指南一(C++11 多執行緒初探)》中只是提到了 std::thread 的基本用法,並給出了一個最簡單的例子,本文將稍微詳細地介紹 std::thread 的用法。 std::thread 在 <thread> 標頭檔案中宣告,因此使用 std::thread 時
基於C++11併發庫的執行緒池與訊息佇列多執行緒框架——std::thread類
1 前言 C++11標準在標準庫中為多執行緒提供了元件,這意味著使用C++編寫與平臺無關的多執行緒程式成為可能,而C++程式的可移植性也得到了有力的保證。 在之前我們主要使用的多執行緒庫要麼是屬於某個單獨平臺的,例如:POSIX執行緒庫(Linux),Windows
C++多執行緒之std::thread
C++11,包含標頭檔案 thread.h,並使用名稱空間std。 thread類提供的方法 方法 描述 thread 建構函式,在這裡傳入執行緒執行函式,和函式引數
C++11併發學習之三:執行緒同步
1.<mutex> 標頭檔案介紹 (1)Mutex系列類(四種) std::mutex,最基本的 Mutex 類。 std::recursive_mutex,遞迴 Mutex 類。 std::time_mutex,定時 Mutex 類。 std::recursive_ti
C++11併發學習之四:執行緒同步(續)
有時候,在第一個執行緒完成前,可能需要等待另一個執行緒執行完成。C++標準庫提供了一些工具可用於這種同步操作,形式上表現為條件變數(condition variable)和期望(future)。 一.條件變數(condition variable) C++標準庫對條件變數有兩套實現:std::c
C++11併發學習之二:執行緒管理
1.啟動執行緒 (1)使用物件 “小試牛刀”中thread構造時傳入的是函式,還可以傳入物件。 #include <thread> #include <iostream> void func() { std::cout<<
C++11 併發指南六( 型別詳解二 std::atomic )
C++11 併發指南六(atomic 型別詳解一 atomic_flag 介紹) 一文介紹了 C++11 中最簡單的原子型別 std::atomic_flag,但是 std::atomic_flag 過於簡單,只提供了 test_and_set 和 clear 兩個 API,不能滿足其他需求(如 s
C++11 併發指南三(std::mutex 詳解)
上一篇《C++11 併發指南二(std::thread 詳解)》中主要講到了 std::thread 的一些用法,並給出了兩個小例子,本文將介紹 std::mutex 的用法。 Mutex 又稱互斥量,C++ 11中與 Mutex 相關的類(包括鎖型別)和函式都宣告在 <mutex> 標頭檔案中
C++11 併發指南五(std::condition_variable 詳解)
前面三講《C++11 併發指南二(std::thread 詳解)》,《C++11 併發指南三(std::mutex 詳解)》分別介紹了 std::thread,std::mutex,std::future 等相關內容,相信讀者對 C++11 中的多執行緒程式設計有了一個最基本的認識,本文將介紹 C++11 標
C++11 併發指南六( 型別詳解二 std::atomic )
C++11 併發指南六(atomic 型別詳解一 atomic_flag 介紹) 一文介紹了 C++11 中最簡單的原子型別 std::atomic_flag,但是 std::atomic_flag 過於簡單,只提供了 test_and_set 和 clear 兩個 API,不能滿足其他需求(如 store
C++11 併發指南四( 詳解三 std::future & std::shared_future)
上一講《C++11 併發指南四(<future> 詳解二 std::packaged_task 介紹)》主要介紹了 <future> 標頭檔案中的 std::packaged_task 類,本文主要介紹 std::future,std::shared_future 以及 std::fu
C++11 併發指南六(atomic 型別詳解三 std::atomic (續))
integral fetch_add(integral, memory_order = memory_order_seq_cst) volatile; integral fetch_add(integral, memory_order = memory_order_seq_cst); integral
C++11 併發指南四( 詳解一 std::promise 介紹)
前面兩講《C++11 併發指南二(std::thread 詳解)》,《C++11 併發指南三(std::mutex 詳解)》分別介紹了 std::thread 和 std::mutex,相信讀者對 C++11 中的多執行緒程式設計有了一個最基本的認識,本文將介紹 C++11 標準中 <future>
C++11 併發指南四( 詳解二 std::packaged_task 介紹)
上一講《C++11 併發指南四(<future> 詳解一 std::promise 介紹)》主要介紹了 <future> 標頭檔案中的 std::promise 類,本文主要介紹 std::packaged_task。 std::packaged_task 包裝一個可呼叫的物件,並且
C++11 併發指南四( 詳解一 std::promise 介紹)
前面兩講《C++11 併發指南二(std::thread 詳解)》,《C++11 併發指南三(std::mutex 詳解)》分別介紹了 std::thread 和 std::mutex,相信讀者對 C++11 中的多執行緒程式設計有了一個最基本的認識,本文將介紹 C++
C++11 併發指南四( 詳解二 std::packaged_task 介紹)
上一講《C++11 併發指南四(<future> 詳解一 std::promise 介紹)》主要介紹了 <future> 標頭檔案中的 std::promise 類,本文主要介紹 std::packaged_task。 std::package