C++11多線程併發中的std::thread、std::mutex和std::future

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_mutexstd::mutex 一樣,也是一種可以被上鎖的對象,但是和 std::mutex 不同的是,std::recursive_mutex 允許同一個線程對互斥量多次上鎖(即遞歸上鎖),來獲得對互斥量對象的多層所有權,std::recursive_mutex 釋放互斥量時需要調用與該鎖層次深度相同次數的 unlock(),可理解爲 lock() 次數和 unlock() 次數相同,除此之外,std::recursive_mutex 的特性和 std::mutex 大致相同。

std::time_mutex 介紹
std::time_mutexstd::mutex多了倆個成員函數,try_lock_for()try_lock_until()
try_lock_for函數接受一個時間範圍,表示在這一段時間範圍之內線程如果沒有獲得鎖則被阻塞住(與std::mutextry_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沒有lockunlock接口,而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函數最爲簡單,如果這個函數的返回是truewait()函數不會被阻塞會直接返回,如果這個函數返回的是falsewait()函數就會堵塞着等待喚醒,如果被僞喚醒,會繼續判斷函數返回值。
例子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::futurestd::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:

  1. std::launch::async 當返回的future失效前會強制執行task,即不調用future.get也會保證task的執行
  2. 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一下,以供後面繼續學習。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章