1. 程式人生 > >c++ 多線程 0

c++ 多線程 0

https 操作 ora 並發 c++ 操作系統 pub 通信 som

1.1 何謂並發

最簡單和最基本的並發,是指兩個或更多獨立的活動同時發生。 (註意區別於計算機中的並發情況!!!!!!!!!!見下面)

1.1.1 計算機系統中的並發:是指在單個系統裏同時執行多個獨立的任務,而非順序的進行一些活動

通過這個任務做一會兒,在切換到別的任務,再做一會兒的方式 ,讓任務看起來是並行執行的,這種方式稱為“任務的切換”,如今仍然叫做 並發。

應為 任務切換的太快 以至於感覺不到任務在何時會被掛起。 任務切換會給用戶造成一種“並發的假象”。因為這種假象,當應用在任務切換的環境下和真

正並發環境下執行相比,行為還是有著微妙的不同。特別是對內存模型不正確的假設,在多線程環境中可能不會出現。

圖1.1顯示了一個計算機處理兩個任務時的理想情景,每個任務被分為10個相等大小的塊。在一個雙核機器上,每個任務可以在各自的處理上執行。 在單核機器上做任務切換時,每個任務的塊交織進行。但中間有一小段分隔; 為實現交織進行,每次從一個任務切換到另一個時都需要切換一次上下文,切換有時間開銷。切換時,操作系統必須為當前運行的任務保存CPU的狀態和指令指針,計算出要切換到哪個任務,並為即將切換到的任務重新加載處理器狀態。 然後,CPU可能要將新任務的指令和數據的內存載入緩存中,這會阻止CPU執行任何指令,從而造成的更多的延遲

技術分享圖片

圖 1.1 並發的兩種方式:雙核機器的真正並行 Vs. 單核機器的任務切換

技術分享圖片

圖 1.2 四個任務在兩個核心之間的切換

技術分享圖片

圖 1.3 一對並發運行的進程之間的通信

技術分享圖片

圖 1.4 同一進程中的一對並發運行的線程之間的通信

清單 1.1 一個簡單的Hello, Concurrent World程序:

#include <iostream>
#include <thread>  //①
void hello()  //②
{
  std::cout << "Hello Concurrent World\n";
}
int main()
{
  std::thread t(hello);  //③
  t.join();  //④
}

④這裏調用join()

的原因 這會導致調用線程(在main()中等待與std::thread對象相關聯的線程,即這個例子中的t。

第2章 線程管理

主要內容

  • 啟動新線程
  • 等待線程與分離線程
  • 線程唯一標識符

2.1.1 啟動線程

1 最簡單的情況下,任務也會很簡單,通常是無參數無返回(void-returning)的函數。這種函數在其所屬線程上運行,直到函數執行完畢,線程也就結束了。

void do_some_work();
std::thread my_thread(do_some_work);

2 將帶有函數調用符類型的實例傳入std::thread類中,替換默認的構造函數。

 class background_task{
   public:
   void operator()() const{  //這個類型重載了運算符()
      do_something();
      do_something_else();
   }
 };
background_task f;
std::thread my_thread(f);

註意 :

當把函數對象傳入到線程構造函數中時,需要避免“最令人頭痛的語法解析”(C++’s most vexing parse, 中文簡介)。

如果你傳遞了一個臨時變量,而不是一個命名的變量;C++編譯器會將其解析為函數聲明,而不是類型對象的定義。

例如:

std::thread my_thread(  background_task()  );

這裏相當與聲明了一個名為my_thread的函數,這函數帶有一個參數(函數指針指向沒有參數並返回background_task對象的函數),返回一個std::thread對象的函數而非啟動了一個線程

使用在前面命名函數對象的方式,或使用多組括號①或使用新統一的初始化語法② lambda表達式也能避免這個問題 也可以避免這個問題。

如下所示:

std::thread my_thread(  ( background_task() )   );  // 1
std::thread my_thread{  background_task()  };    // 2

==============================================================

啟動了線程,你需要明確是要等待線程結束(join),還是讓其自主運行(detach分離式)。

如果std::thread對象銷毀之前還沒有做出決定,程序就會終止(std::thread的析構函數會調用std::terminate())。

因此,即便是有異常存在,也需要確保線程能夠正確的加入(joined)或分離(detached)。

c++ 多線程 0