C++11 新標準中引入了五個頭文件來支持多線程編程:<atomic>,<thread>,<mutex>,<condition_variable> 和 <future>
<atomic>: 該文件主要申明瞭倆個類,std::atomic 和 std::atomic_flag,另外還聲明瞭一套 C 風格的原子類和與C兼容的原子操作的函數。
<thread>: 該文件主要聲明瞭 std::thread 類,另外std::thread 命名空間也在該頭文件中。
<mutex>: 該頭文件主要聲明瞭與互斥量(mutex)相關的類,包括 std::mutex 系列類,std::lock_guard, std::unique_lock,以及其他的類型和函數。
<condition_variable>:該頭文件主要聲明瞭與條件變量相關的類,包括 std::condition_variable 和 std::condition_variable_any。
<future>:該頭文件主要聲明瞭 std::promise, std::package_task 兩個 Provider 類,以及 std::future 和 std::shared_future 兩個 Future 類,另外還有一些與之相關的類型和函數,std::async() 函數就聲明在此頭文件中。
一. 類std::thread
1.默認構造函數:thread() noexcept;
構造一個任何線程都不執行的線程對象,即空的thread執行對象。
2.初始化函數:
template <class Fn, class... Args>
explicit thread (Fn&& fn, Args&&... args);
構造一個線程對象,可以開啓線程執行,該thread對象可被joinable,新執行的線程調用函數fn,並傳遞args作爲參數:
fn
:可以指向函數,指向成員,或是移動構造函數
args
:傳遞給fn的參數,這些參數可以移動賦值構造。如果fn是一個成員指針,那麼第一個args參數就必須是一個對象,或是引用,或是指向該對象的指針。
3.拷貝構造函數 (被禁用):thread (const thread&) = delete
,意味着thread不可被拷貝構造。
4.move構造函數 (移動構造函數):thread (thread && x)noexcept
調用成功後x不代表任何thread執行對象。
std::thread::join
該函數返回時,線程執行完成。
當 一個 thread 調用Join方法的時候,MainThread 就被停止執行,直到該 thread 線程執行完畢。
注意:可被joinable的thread對象必須在他們銷燬之前被主線程join或者將其設置爲detached。
#include <iostream>
#include <thread> // std::thread, std::this_thread::sleep_for
#include <chrono> // std::chrono::seconds
void pause_thread(int n)
{
std::this_thread::sleep_for (std::chrono::seconds(n));
std::cout << "pause of " << n << " seconds ended\n";
}
int main()
{
std::cout << "Spawning 3 threads...\n";
std::thread t1 (pause_thread,1);
std::thread t2 (pause_thread,2);
std::thread t3 (pause_thread,3);
std::cout << "Done spawning threads. Now waiting for them to join:\n";
t1.join(); //停下主線程,進入t1 線程
t2.join(); //進入t2線程
t3.join(); // 進入t3線程
std::cout << "All threads joined!\n";
return 0;
}
std::thread::detach
分離線程的對象,使他們彼此獨立地執行所表示的線程。這倆個線程既沒有被阻止,也沒有以任何方式同步。當任一結束執行,其資源被釋放。
#include <iostream> // std::cout
#include <thread> // std::thread, std::this_thread::sleep_for
#include <chrono> // std::chrono::seconds
void pause_thread(int n)
{
std::this_thread::sleep_for (std::chrono::seconds(n));
std::cout << "pause of " << n << " seconds ended\n";
}
int main()
{
std::cout << "Spawning and detaching 3 threads...\n";
std::thread (pause_thread,1).detach();
std::thread (pause_thread,2).detach();
std::thread (pause_thread,3).detach();
std::cout << "Done spawning threads.\n";
std::cout << "(the main thread will now pause for 5 seconds)\n";
// give the detached threads time to finish (but not guaranteed!):
pause_thread(5);
return 0;
}
//輸出
Output (after 5 seconds):
Spawning and detaching 3 threads...
Done spawning threads.
(the main thread will now pause for 5 seconds)
pause of 1 seconds ended
pause of 2 seconds ended
pause of 3 seconds ended
pause of 5 seconds ended
更多的thread中的join()和detach()例子。
是否一定要加join()或者detach()呢?其實是不一定的! 看下面程序:
#include<thread>
#include<iostream>
#include <unistd.h>
using namespace std;
class Test{
public:
void run(int num);
};
void Test::run(int num){
int count=100;
while(count>0){
std::cout<<"aaaa: "<<num<<std::endl;
count--;
}
}
class Test2{
private:
Test* testClass;
public:
int printNum(int inputNum){
cout <<"Test2:"<<inputNum<<endl;
}
void setTestClass(Test* testClassInput){
testClass = testClassInput;
}
};
class System{
private:
Test2* pTest2;
Test* pTest;
public:
System(){
//在主線程運行
pTest2 = new Test2();
//開劈新的線程
pTest = new Test();
std::thread* ptTest = new thread(&Test::run, pTest,1);
pTest2->setTestClass(pTest);
}
void printNumViaTest2(int num){
pTest2->printNum(num);
}
};
int main (){
System test;
for(int i=0; i<1000; i++){
test.printNumViaTest2(i);
}
//usleep(1000);
return 0;
}
在上述程序中,沒有調用join() 或者 detach() 函數,但是該程序可以正常運行,主要是因爲線程在運行的時候,主進程還未退出。有時候,若不用join() 或者 detach() 可能會出現terminate called without an active exception Aborted
的錯誤,這是因爲線程還在運行的時候,主進程就退出了。
初始化 thread 類的構造函數
對於類的成員函數,我們需要給出類對象的地址:
#include <iostream>
#include <thread>
using namespace std;
class A
{
public:
void fun(int a,int b)
{
std::cout<<"this is a thread"<<std::endl;
}
};
int main()
{
int k=0;
A a;
std::thread t(&A::fun,a,k,k+1);
t.detach();
return 0;
}
std::thread(&A::fun,a,k,k+1); 這個地方就可以看出thread 類的構造對於成員函數的重載了,std::thread t(函數(成員函數)地址,對象地址,成員函數的參數1,參數2,參數3...)。
相比非成員函數,成員函數需要給出類實例化對象的地址,如果該線程是在同一類的某一成員函數當中被構造,則直接用this 關鍵字代替即可。
二. std::mutex
1.Mutex系列類:
std::mutex,最基本的Mutex類
std::recursive_mutex,遞歸Mutex類
std::time_mutex,定時Mutex類
std::recursive_timed_mutex,定時遞歸Mutex類
2.Lock類
std::lock_guard,與Mutex RAII相關,方便線程對互斥量上鎖。
std::unique_lock,與Mutex RAII相關,方便線程對互斥量上鎖,但提供了更好的上鎖和解鎖控制。
3.函數
std::try_lock,嘗試同時對多個互斥量上鎖。
std::lock,可以同時對多個互斥量上鎖。
std::call_one,如果多個線程需要同時調用某個函數,call_once可以保證多個線程對該函數只調用一次。
std::mutex 介紹
std::mutex 是C++11中最基本的互斥量,std::mutex對象提供了獨佔所有權的特性—即不支持遞歸地對std::mutex對象上鎖,而std::recursize_lock則可以遞歸地對互斥量對象上鎖。
std::mutex 成員函數
1.構造函數,std::mutex不允許拷貝構造,也不允許move拷貝,最初產生的mutex對象是unlocked狀態的。
2.lock(), 調用線程將鎖住該互斥量。線程調用該函數會發生下面3種情況: (1) 如果該互斥量當前沒有被鎖住,則調用線程將該互斥量鎖住,直到調用unlock之前,該線程一直擁有該鎖。(2) 如果當前互斥量被其他線程鎖住,則當前的調用線程被阻塞。(3) 如果當前互斥量被當前調用線程鎖住,則會產生死鎖,故lock()後一般需要 unlock()。
3.unlock(), 解鎖,釋放對互斥量所有權。
4.try_lock(), 嘗試鎖住互斥量,如果互斥量被其他線程佔有,則當前線程也不會被堵塞。出現3種情況:(1) 如果當前互斥量沒有被其他鎖住,則鎖住該互斥量。 (2) 如果當前互斥量被其他線程鎖住,則當前調用線程返回false,不會堵塞。(3)如果被當前線程鎖住了但沒有釋放,產生死鎖。
加鎖和解鎖問題
因爲我們創造的每一個線程只要在一個進程內,都是共享內存池的,這樣在讀寫數據可能會發生混亂。
C++11提供了mutex類進行加鎖和解鎖。
#include <iostream>
#include <thread>
#include <mutex>
std::mutex mut;
class A{
public:
volatile int temp;
A(){
temp=0;
}
void fun(int num){
int count=10;
while(count>0){
mut.lock();
temp++;
std::cout<<"thread_"<<num<<"...temp="<<temp<<std::endl;
mut.unlock();
count--;
}
}
void test(int num){
for(a;a<10;a++){
mut.lock();
std::cout<<"thread_"<<num<<"...a="<<a<<std::endl;
mut.unlock();
}
}
void thread_run(){
std::thread t1(&A::fun,this,1); //同一個類
std::thread t2(&A::fun,this,2);
std::thread t3(&A::test,this,3);
t1.join();
t2.join();
t3.join();
}
int a=0;
};
int main(){
A a;
a.thread_run();
}
volatile和const關鍵很相似,都是修飾變量的,只是二者功能不一樣。
volatile在多線程當中經常使用,因爲在某一線程多次調用某一個變量,編譯器會進行優化,將該變量存放在在寄存器當中,(在程序運行時,根據需要到內存中相應的存儲單元中調用,如果一個變量在程序中頻繁使用,例如循環變量,那麼,系統就必須多次訪問內存中的該單元,影響程序的執行效率。因此,C\C++語言還定義了一種變量,不是保存在內存上,而是直接存儲在CPU中的寄存器中,這種變量稱爲寄存器變量。)
不會每次都從內存當中讀入。如果該變量同時在其他線程當中被修改,這樣就會發生讀取錯誤。而加上volatile修飾,則會提醒編譯器,這個變量可能會被改變,不能存放到寄存器當中,需要每次都從內存當中讀取。
try_lock():
#include <iostream> // std::cout
#include <thread> // std::thread
#include <mutex> // std::mutex
volatile int counter(0); // non-atomic counter
std::mutex mtx; // locks access to counter
void attempt_10k_increases() {
for (int i=0; i<10000; ++i) {
if (mtx.try_lock()) { // only increase if currently not locked:
++counter;
mtx.unlock();
}
}
}
int main (int argc, const char* argv[]) {
std::thread threads[10];
for (int i=0; i<10; ++i)
threads[i] = std::thread(attempt_10k_increases);
for (auto& th : threads) th.join();
std::cout << counter << " successful increases of the counter.\n";
return 0;
}
std::recursive_mutex 介紹
std::recursive_mutex
與 std::mutex
一樣,也是一種可以被上鎖的對象,但是和 std::mutex
不同的是,std::recursive_mutex
允許同一個線程對互斥量多次上鎖(即遞歸上鎖),來獲得對互斥量對象的多層所有權,std::recursive_mutex
釋放互斥量時需要調用與該鎖層次深度相同次數的 unlock()
,可理解爲 lock()
次數和 unlock()
次數相同,除此之外,std::recursive_mutex
的特性和 std::mutex
大致相同。
std::time_mutex 介紹
std::time_mutex
比std::mutex
多了倆個成員函數,try_lock_for()
,try_lock_until()
。
try_lock_for
函數接受一個時間範圍,表示在這一段時間範圍之內線程如果沒有獲得鎖則被阻塞住(與std::mutex
的try_lock()
不同,try_lock
如果被調用時沒有獲得鎖則直接返回false
),如果在此期間其他線程釋放了鎖,則該線程可以獲得對互斥量的鎖,如果超時(即在指定時間內還是沒有獲得鎖),則返回false。
try_lock_until
函數則接受一個時間點作爲參數,在指定時間點未到來之前線程如果沒有獲得鎖則被阻塞住,如果在此期間其他線程釋放了鎖,則該線程可以獲得對互斥量的鎖,如果超時(即在指定時間內還是沒有獲得鎖),則返回 false
。
#include <iostream> // std::cout
#include <chrono> // std::chrono::milliseconds
#include <thread> // std::thread
#include <mutex> // std::timed_mutex
std::timed_mutex mtx;
void fireworks() {
//等待加鎖: each thread prints "-" every 200ms:
while (!mtx.try_lock_for(std::chrono::milliseconds(200))) {
std::cout << "-";
}
// 獲得鎖! - wait for 1s, then this thread prints "*"
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
std::cout << "*\n";
mtx.unlock();
}
int main ()
{
std::thread threads[10];
// spawn 10 threads:
for (int i=0; i<10; ++i)
threads[i] = std::thread(fireworks);
for (auto& th : threads) th.join();
return 0;
}
std::lock_guard 介紹
#include <iostream> // std::cout
#include <thread> // std::thread
#include <mutex> // std::mutex, std::lock_guard
#include <stdexcept> // std::logic_error
std::mutex mtx;
void print_even (int x) {
if (x%2==0) std::cout << x << " is even\n";
else throw (std::logic_error("not even"));
}
void print_thread_id (int id) {
try {
// using a local lock_guard to lock mtx guarantees unlocking on destruction / exception:
std::lock_guard<std::mutex> lck (mtx);
print_even(id);
}
catch (std::logic_error&) {
std::cout << "[exception caught]\n";
}
}
int main (){
std::thread threads[10];
// spawn 10 threads:
for (int i=0; i<10; ++i)
threads[i] = std::thread(print_thread_id,i+1);
for (auto& th : threads) th.join();
return 0;
}
std::unique_lock 介紹
與 Mutex RAII 相關,方便線程對互斥量上鎖,但提供了更好的上鎖和解鎖控制。
#include <iostream> // std::cout
#include <thread> // std::thread
#include <mutex> // std::mutex, std::unique_lock
std::mutex mtx; // mutex for critical section
void print_block (int n, char c) {
// critical section (exclusive access to std::cout signaled by lifetime of lck):
std::unique_lock<std::mutex> lck (mtx); //在lck的生命週期內對mtx嘗試上鎖,lck生命週期結束時自動解鎖
for (int i=0; i<n; ++i) {
std::cout << c;
}
std::cout << '\n';
}
int main (){
std::thread th1 (print_block,50,'*');
std::thread th2 (print_block,50,'$');
th1.join();
th2.join();
return 0;
}
三. std::condition_variable
使用條件變量來實現生產者/消費者模型:
一種重要的模型,基於等待/通知機制。生產者/消費者模型描述的是有一塊緩衝區作爲倉庫,生產者可將產品放入倉庫,消費者可以從倉庫中取出產品,生產者/消費者模型關注的是以下幾個點:
- 生產者生產的時候消費者不能消費
- 消費者消費的時候生產者不能生產
- 緩衝區空時消費者不能消費
- 緩衝區滿時生產者不能生產
一共有三種關係:生產者與生產者的互斥關係,消費者與消費者的互斥關係,生產者與消費者的互斥且同步關係。
std::condition_variable
是條件變量,當std::condition_variable
對象的某個wait函數被調用的時候,它使用std::unique_lock
(通過std::mutex
)來鎖住當前線程。當前線程會一直被堵塞,直到另一個線程在相同的std::condition_variable
對象上調用了notification
(有notify_all()
和 notify_one()
)函數來喚醒當前線程。
在消費者生產者模型中,如果消費者法線隊列中沒有東西,就可以讓自己休眠,但是不能一直不幹活呀,通過notify_one()
就是喚醒處於wait
中一個變量或者通過判斷隊列是否爲空來實現自身喚醒。
這裏解釋下爲啥在管理互斥鎖的時候,使用的是std::unique_lock
而不是std::lock_guard
,事實上也不能使用std::lock_guard
,這裏需要解釋下wait()
函數所做的事情。可以看到,在wait()
函數之前,使用互斥鎖保護了,如果wait
的時候什麼都不做,會一直持有互斥鎖,那麼不能夠將數據放入隊列中 (看例子2)。所以,wait()
函數會先調用互斥鎖的unlock()
函數,然後再將自己睡眠,在被喚醒後,又會繼續持有鎖,保護後面的隊列操作。而lock_guard
沒有lock
和unlock
接口,而unique_lock
提供了。這就是必須使用unique_lock
的原因。
例子1如下:
#include <iostream> // std::cout
#include <thread> // std::thread
#include <mutex> // std::mutex, std::unique_lock
#include <condition_variable> // std::condition_variable
std::mutex mtx; // 全局互斥鎖.
std::condition_variable cv; // 全局條件變量.
bool ready = false; // 全局標誌位.
void do_print_id(int id)
{
std::unique_lock <std::mutex> lck(mtx);
while (!ready) // 如果標誌位不爲 true, 則等待...
cv.wait(lck); // 當前線程被阻塞, 當全局標誌位變爲 true 之後,
// 線程被喚醒, 繼續往下執行打印線程編號id.
std::cout << "thread " << id << '\n';
}
void go()
{
std::unique_lock <std::mutex> lck(mtx);
ready = true; // 設置全局標誌位爲 true.
cv.notify_all(); // 喚醒所有線程.
}
int main()
{
std::thread threads[10];
// spawn 10 threads:
for (int i = 0; i < 10; ++i)
threads[i] = std::thread(do_print_id, i);
std::cout << "10 threads ready to race...\n";
go(); // go!
for (auto & th:threads)
th.join();
return 0;
}
執行結果如下:
threads ready to race...
thread 1
thread 0
thread 2
thread 3
thread 4
thread 5
thread 6
thread 7
thread 8
thread 9
在例子1中使用了cv.wait(lck)
的寫法;換一種寫法,wait()
的第二個參數可以傳入一個函數表示檢查條件,這裏使用lambda
函數最爲簡單,如果這個函數的返回是true
,wait()
函數不會被阻塞會直接返回,如果這個函數返回的是false
,wait()
函數就會堵塞着等待喚醒,如果被僞喚醒,會繼續判斷函數返回值。
例子2如下:
#include <iostream>
#include <deque>
#include <thread>
#include <mutex>
#include <condition_variable>
std::deque<int> q;
std::mutex mu;
std::condition_variable cond;
void producer() {
int count = 10;
while (count > 0) {
std::unique_lock<std::mutex> locker(mu);
q.push_front(count);
locker.unlock();
cond.notify_one(); // Notify one waiting thread, if there is one.
std::this_thread::sleep_for(std::chrono::seconds(1));
count--;
}
}
void customer() {
int data = 0;
while ( data != 1) {
std::unique_lock<std::mutex> locker(mu);
//lambda語法
cond.wait(locker,[&]{return !q.empty();}); // Unlock mu and wait to be notified
data = q.back();
q.pop_back();
locker.unlock();
std::cout << "t2 got a value from t1: " << data << std::endl;
}
}
int main() {
std::thread t1(producer);
std::thread t2(customer);
t1.join();
t2.join();
return 0;
}
執行結果如下:
t2 got a value from t1: 10
t2 got a value from t1: 9
t2 got a value from t1: 8
t2 got a value from t1: 7
t2 got a value from t1: 6
t2 got a value from t1: 5
t2 got a value from t1: 4
t2 got a value from t1: 3
t2 got a value from t1: 2
t2 got a value from t1: 1
四. std::future
std::future
可以用來獲取異步任務的結果,因此可以把它當成一種簡單的線程間同步手段。std::future
通常由某個Provider創建,可以把Provider想象成一個異步任務的提供者,Provider在某個線程中設置共享狀態的值,與該共享狀態相關聯的std::future
對象調用get (通常在另外一個線程中) 獲取該值,如果共享狀態的標誌不爲ready,則調用std::future::get
會阻塞當前的調用者,知道Provider設置了共享狀態的值(此時共享狀態的標誌變爲ready),std::future::get
返回異步任務的值或異常(如果發生了異常)。
一個有效(valid)的std::future
對象只有在有效(valid)的情況下才有用,由std::future
默認構造函數創建的future
對象不是有效的(除非當前非有效的future
對象被move
賦值另一個有效的future
對象)。
在一個有效的std::future
對象上調用get
會阻塞當前的調用者,直到Provider設置了共享狀態的值或異常(此時共享狀態的標誌變爲ready),std::future::get
將返回異步任務的值或異常(如果發生了異常)。std::future
對象通常由以下三種Provider創建,並和某個共享狀態相關聯。Provider可以是函數或者類,分別是:
std::async函數
std::promise::get_future, get_future爲promise類的成員函數。
std::packaged_task::get_future, 此時get_future爲packaged_task的成員函數
以下主要講下由async
創建的std::future
:
1. std::async和std::future
std::async
創建一個後臺線程執行傳遞的任務,這個任務只要是callable object
均可,然後返回一個std::future
。std::future
存儲一個多線程共享的狀態,當調用future.get()
是會阻塞直到綁定的task執行完畢。
Example 1:
#include <iostream>
#include <future>
void task(){
for(int i=0; i<10; i++){
std::cout << "A";
}
}
int main(){
//創建異步任務,任務返回值保存在std::future中
std::future<void> result{std::async(task)};
//執行其他任務
for(int i=0;i<10;i++){
std::cout << "B";
}
for(int j=0;j<10;j++){
std::cout<<"C";
}
//需要異步任務結果的時候,如果沒有返回,那麼會等待至返回,get操作會阻塞
result.get();
system("pause");
return 0;
}
輸出:
BBBBBBBBBBCCCCCCCCCCAAAAAAAAAA
Example 2:
#include <iostream>
#include <future>
void task(){
for(int i=0; i<10; i++){
std::cout << "A";
}
}
int main(){
std::future<void> result{std::async(task)};
result.get();
for(int i=0;i<10;i++){
std::cout << "B";
}
system("pause");
return 0;
}
輸出:
AAAAAAAAAABBBBBBBBBB
2. std::launch::async
上面task返回void,這個結果沒有用,我們只是單純的想等待任務線程結束。
對這種需要還可以用更簡單的方法:指定一個launch policy
Example 1:
#include <iostream>
#include <future>
void task(){
for(int i=0; i<10; i++){
std::cout << "A";
}
}
int main(){
std::future<void> result{std::async(std::launch::async, task)};
for(int i=0;i<10;i++){
std::cout << "B";
}
system("pause");
return 0;
}
輸出
BBBBBBBBBBAAAAAAAAAA
在創建async的時指定一個lauch policy,連result.get都可以不用了,不過還是需要把async的返回值賦給result。
Example 2:
#include <iostream>
#include <future>
void task(){
for(int i=0; i<10; i++){
std::cout << "A";
}
}
int main(){
std::future<void> result{std::async(std::launch::async, task)};
result.get();
for(int i=0;i<10;i++){
std::cout << "B";
}
system("pause");
return 0;
}
輸出
AAAAAAAAAABBBBBBBBBB
3.std::launch::deferred
總共有倆種launch policy:
std::launch::async
當返回的future
失效前會強制執行task,即不調用future.get也會保證task的執行std::launch::deferred
僅當調用future.get
時候纔會執行task, 如果創建async時不指定launch policy,會默認std::launch::async | std::launch::deferred
,根據情況選一種執行
Example 1:
#include <iostream>
#include <future>
void task() {
for (int i = 0; i < 10; i++) {
std::cout << "A";
}
}
int main() {
std::future<void> result{ std::async(std::launch::deferred,task) };
for (int i = 0; i < 10; i++) {
std::cout << "B";
}
result.get(); //加了.get()
system("pause");
return 0;
}
輸出:
BBBBBBBBBBAAAAAAAAAA
Example 2:
#include <iostream>
#include <future>
void task(){
for(int i=0; i<10; i++){
std::cout << "A";
}
}
**Example 1:**
int main(){
std::future<void> result{std::async(std::launch::deferred, task)}; //沒有調用.get()
for(int i=0;i<10;i++){
std::cout << "B";
}
system("pause");
return 0;
}
輸出:
BBBBBBBBBB
Another example:
#include<iostream>
#include<thread>
#include<string>
#include<vector>
#include<list>
#include<mutex>
#include<future>
using namespace std;
int mythread() //線程入口函數
{
cout << "mythread start" << "threadid= " << std::this_thread::get_id() << endl; //打印線程id
std::chrono::milliseconds dura(5000); //定一個5秒的時間
std::this_thread::sleep_for(dura); //休息一定時常
cout << "mythread end" << "threadid= " << std::this_thread::get_id() << endl; //打印線程id
return 5;
}
int main()
{
cout << "main" << "threadid= " << std::this_thread::get_id() << endl;
//std::future<int> result = std::async(mythread);//流程並不卡在這裏,讓程序決定是否開啓新的線程
std::future<int> result = std::async(std::launch::async, mythread);//開啓新的線程,mythread和mainthread的線程id是不同的。
cout << "continue....." << endl;
//枚舉類型
std::future_status status = result.wait_for(std::chrono::seconds(0));//等待一秒
if (status == std::future_status::deferred)
{
//線程被延遲執行了,系統資源緊張
cout << result.get() << endl; //此時採取調用mythread()
}
else if (status == std::future_status::timeout)//
{
//超時:表示線程還沒執行完;我想等待你1秒,希望你返回,你沒有返回,那麼 status = timeout
//線程還沒執行完
cout << "超時:表示線程還沒執行完!" << endl;
}
else if (status == std::future_status::ready)
{
//表示線程成功返回
cout << "線程成功執行完畢,返回!" << endl;
cout << result.get() << endl;
}
cout << "I love China!" << endl;
return 0;
}
更深入的如std::atomic
請移步https://www.cnblogs.com/haippy/p/3284540.html,非常好的C++11併發的版塊,也mark一下,以供後面繼續學習。