c++11 多線程(1) thread 總結(jié)


本文主要是針對(duì)C++中多線程并發(fā)操作參見(cplusplus)進(jìn)行解釋,文章從下面幾個(gè)方面進(jìn)行學(xué)習(xí),分別介紹多線程中會(huì)使用到的幾個(gè)文件學(xué)習(xí)。 文中代碼 可編譯運(yùn)行版本已上傳在本人github(地址)

多線程

C++ 中關(guān)于并發(fā)多線程的部分,主要包含 <thread>、<mutex>、<atomic>、<condition_varible>、<future>五個(gè)部分。

  • <atomic>:該頭文主要聲明了兩個(gè)類, std::atomic 和 std::atomic_flag,另外還聲明了一套 C 風(fēng)格的原子類型和與 C 兼容的原子操作的函數(shù)。
  • <thread>:該頭文件主要聲明了 std::thread 類,另外 std::this_thread 命名空間也在該頭文件中。
  • <mutex>:該頭文件主要聲明了與互斥量(mutex)相關(guān)的類,包括 std::mutex 系列類,std::lock_guard, std::unique_lock, 以及其他的類型和函數(shù)。
  • <condition_variable>:該頭文件主要聲明了與條件變量相關(guān)的類,包括 std::condition_variable 和 std::condition_variable_any。
  • <future>:該頭文件主要聲明了 std::promise, std::package_task 兩個(gè) Provider 類,以及 std::future 和 std::shared_future 兩個(gè) Future 類,另外還有一些與之相關(guān)的類型和函數(shù),std::async() 函數(shù)就聲明在此頭文件中。

1、 thread

本節(jié)講thread頭文件中的內(nèi)容,練習(xí)代碼地址;
<thread> 頭文件中聲明:thread線程和命名空間this_thread; thread包含如下:

(一)、Member types
id Thread id (public member type )
native_handle_type Native handle type (public member type )

std::thread::id是線程調(diào)用get_id和this_thread::get_id的返回值;thread::id默認(rèn)構(gòu)造函數(shù)的結(jié)果是一個(gè)non-joinable的值;通常用來和其他線程 thread::get_id的結(jié)果做比較。
std::thread::native_handle_type本地句柄類型,如果庫實(shí)現(xiàn)支持它,這個(gè)成員類型只存在于類線程中。是thread類成員函數(shù)thread::native_handle的返回值。
定義: typedef /* implementation-defined */ native_handle_type;

(二)、Member functions
(constructor) Construct thread (public member function )
(destructor) Thread destructor (public member function )
operator= Move-assign thread (public member function )
get_id Get thread id (public member function )
joinable Check if joinable (public member function )
join Join thread (public member function )
detach Detach thread (public member function )
swap Swap threads (public member function )
native_handle Get native handle (public member function )
hardware_concurrency [static] Detect hardware concurrency (public static member function )

示例 1:

// thread example
#include  <iostream>        // std::cout
#include  <thread>        // std::thread
void foo()  { 
    std::cout << "foo is called" << std::endl;
}
void bar(int x) {
     std::cout << "bar is called" << std::endl;
}

int main()
{
     std::thread first (foo);    // spawn new thread that calls foo()
     std::thread second (bar,0);  // spawn new thread that calls bar(0)                                                 
     std::cout << "main, foo and bar now execute concurrently...\n";
     // synchronize threads:
     first.join();                // pauses until first finishes
     second.join();              // pauses until second finishes
     std::cout << "foo and bar completed.\n";
     return 0;
}
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)                 thread (thread&& x) noexcept;

(1)默認(rèn)構(gòu)造函數(shù)
構(gòu)造一個(gè)不表示任何執(zhí)行線程的線程對(duì)象。
(2)初始化的構(gòu)造函數(shù) 模版函數(shù)
構(gòu)建一個(gè)線程對(duì)象,該對(duì)象表示一個(gè)新的可接合線程。新的執(zhí)行線程調(diào)用fn傳遞args作為參數(shù)(使用其lvalue或rvalue引用的衰變副本)。此構(gòu)建的完成開始同步調(diào)用fn副本的。
(3) 拷貝構(gòu)造 不允許拷貝構(gòu)造
(4) 移動(dòng)構(gòu)造 構(gòu)造線程獲取x線程,這個(gè)操作不會(huì)影響移動(dòng)線程的執(zhí)行,它只會(huì)傳輸它的處理程序。完成x將不再表示一個(gè)線程。
示例2

  // constructing threads
  #include <iostream>       // std::cout
  #include <atomic>         // std::atomic
  #include <thread>         // std::thread
  #include <vector>         // std::vector

  std::atomic<int> global_counter (0);

  void increase_global (int n) { for (int i=0; i<n; ++i) ++global_counter; }

  void increase_reference (std::atomic<int>& variable, int n) { for (int i=0;   i<n; ++i) ++variable; }

  struct C : std::atomic<int> {
    C() : std::atomic<int>(0) {}
    void increase_member (int n) { for (int i=0; i<n; ++i) fetch_add(1); }
  };

  int main ()
  {
    std::vector<std::thread> threads;

    std::cout << "increase global counter with 10 threads...\n";
    for (int i=1; i<=10; ++i)
      threads.push_back(std::thread(increase_global,1000));

    std::cout << "increase counter (foo) with 10 threads using   reference...\n";
    std::atomic<int> foo(0);
    for (int i=1; i<=10; ++i)
    {
        threads.push_back(std::thread(increase_reference,std::ref(foo),1000));
    }

    std::cout << "increase counter (bar) with 10 threads using member...\n";
    C bar;
    for (int i=1; i<=10; ++i)
    {
      threads.push_back(std::thread(&C::increase_member,std::ref(bar),1000))  ;
    }

    std::cout << "synchronizing all threads...\n";
    for (auto& th : threads) th.join();

    std::cout << "global_counter: " << global_counter << '\n';
    std::cout << "foo: " << foo << '\n';
    std::cout << "bar: " << bar << '\n';

    return 0;
  }
  • 析構(gòu)函數(shù)(destructor)
    std::thread::~thread破壞了線程對(duì)象。如果在銷毀時(shí)線程是可接合的,則調(diào)用終止()。
  • std::thread::operator=:
    move (1) thread& operator= (thread&& rhs) noexcept;
    copy [deleted] (2) thread& operator= (const thread&) = delete;
    thread不允許拷貝;如果對(duì)象當(dāng)前不是joinable的,它將獲得由rhs(如果有的話)表示的執(zhí)行線程。如果是joinable,則調(diào)用終止()。賦值“=”運(yùn)算符通過右值表達(dá)式,復(fù)制后的thread對(duì)象不再是一個(gè)線程。
    示例3
  // example for thread::operator=
  #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::thread threads[5];                         // default-constructed threads

    std::cout << "Spawning 5 threads...\n";
    for (int i=0; i<5; ++i)
      threads[i] = std::thread(pause_thread,i+1);   // move-assign threads

    std::cout << "Done spawning threads. Now waiting for them to join:\n";
    for (int i=0; i<5; ++i)
      threads[i].join();

    std::cout << "All threads joined!\n";

    return 0;
  }
  • std::thread::get_id
    如果線程對(duì)象是joinable,函數(shù)將返回唯一標(biāo)識(shí)線程的值。
    如果線程對(duì)象不可joinable,函數(shù)將返回成員類型線程的默認(rèn)構(gòu)造對(duì)象:id。
    示例4
  // thread::get_id / this_thread::get_id
  #include <iostream>       // std::cout
  #include <thread>         // std::thread, std::thread::id,   std::this_thread::get_id
  #include <chrono>         // std::chrono::seconds
 
  std::thread::id main_thread_id = std::this_thread::get_id();

  void is_main_thread() {
    if ( main_thread_id == std::this_thread::get_id() )
      std::cout << "This is the main thread.\n";
    else
      std::cout << "This is not the main thread.\n";
  }

  int main() 
  {
    is_main_thread();
    std::thread th (is_main_thread);
    th.join();
  }
  • std::thread::joinable
    返回線程對(duì)象是否可joinable。
    如果線程對(duì)象表示執(zhí)行的線程,則是可joinable。
    在這些情況下,一個(gè)線程對(duì)象是不可連接的:

    • 如果是默認(rèn)構(gòu)造。
    • 如果它已經(jīng)被移動(dòng)(或者構(gòu)造另一個(gè)線程對(duì)象,或者分配給它)。
    • 如果它的成員加入或分離被調(diào)用。

    示例5

  // example for thread::joinable
  #include <iostream>       // std::cout
  #include <thread>         // std::thread
 
  void mythread() 
  {
    // do stuff...
  }
 
  int main() 
  {
    std::thread foo;
    std::thread bar(mythread);

    std::cout << "Joinable after construction:\n" << std::boolalpha;
    std::cout << "foo: " << foo.joinable() << '\n';
    std::cout << "bar: " << bar.joinable() << '\n';

    if (foo.joinable()) foo.join();
    if (bar.joinable()) bar.join();

    std::cout << "Joinable after joining:\n" << std::boolalpha;
    std::cout << "foo: " << foo.joinable() << '\n';
    std::cout << "bar: " << bar.joinable() << '\n';

    return 0;
  }
  • std::thread::join
    join 函數(shù)在線程執(zhí)行完成的時(shí)候返回;此函數(shù)在函數(shù)返回時(shí)與線程中所有操作的完成是同步的;調(diào)用join直到j(luò)oin被構(gòu)造函數(shù)調(diào)用返回間,阻塞調(diào)用的線程;在調(diào)用此函數(shù)之后,線程對(duì)象變得不可連接,可以安全地銷毀。
    示例6
  // example for thread::join
  #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 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();
    t2.join();
    t3.join();
    std::cout << "All threads joined!\n";

    return 0;
  }
  • std::thread::detach
    detach分離出調(diào)用線程對(duì)象所代表的線程,允許它們彼此獨(dú)立地執(zhí)行;這兩個(gè)線程在任何方式上都不阻塞或同步;注意,當(dāng)一個(gè)結(jié)束執(zhí)行時(shí),它的資源被釋放。在調(diào)用此函數(shù)之后,線程對(duì)象變得不可連接,可以安全地銷毀。
    示例7
  #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;
  }
  • std::thread::swap
    void swap (thread& x) noexcept; // 與X交換對(duì)象狀態(tài)。

  • std::thread::native_handle
    獲取本地處理函數(shù);如果庫實(shí)現(xiàn)支持,這個(gè)成員函數(shù)只存在于類線程中;如果存在,它將返回用于訪問與線程關(guān)聯(lián)的特定于實(shí)現(xiàn)的信息的值。

  • std::thread::hardware_concurrency
    static unsigned hardware_concurrency() noexcept; //函數(shù)定義
    檢測硬件并發(fā),返回硬件線程上下文的數(shù)量。對(duì)這個(gè)值的解釋是看具體的系統(tǒng)和實(shí)現(xiàn),可能不是精確的,只是一個(gè)近似值。請(qǐng)注意,這并不需要匹配系統(tǒng)中可用的處理器或內(nèi)核的實(shí)際數(shù)目:一個(gè)系統(tǒng)可以支持每個(gè)處理單元的多個(gè)線程,或者限制對(duì)程序的資源的訪問。如果此值沒有計(jì)算或被定義好,則函數(shù)返回0。

  • std::swap (thread)
    std::swap 跟前面提到的成員函數(shù)有所不同,他不是成員函數(shù)。函數(shù)定義:
    void swap (thread& x, thread& y) noexcept;
    交換線程對(duì)象x和y的狀態(tài);就像x.swap(y)被調(diào)用。

本文主要講thread,下篇c++11 多線程(2)mutex總結(jié)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,362評(píng)論 6 537
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,013評(píng)論 3 423
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 177,346評(píng)論 0 382
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經(jīng)常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,421評(píng)論 1 316
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,146評(píng)論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,534評(píng)論 1 325
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,585評(píng)論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,767評(píng)論 0 289
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,318評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,074評(píng)論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,258評(píng)論 1 371
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,828評(píng)論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,486評(píng)論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,916評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,156評(píng)論 1 290
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 51,993評(píng)論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,234評(píng)論 2 375

推薦閱讀更多精彩內(nèi)容