并行:允許多個執行流同時執行(要求多個處理器);
并發:多個執行流可以不按照一個特定的順序執行。

并發性的來源:程序會調用作業系統的API,作業系統在并發執行兩個執行流的時候,要保證它們互不幹擾,是以,對處理器和記憶體提出了要求。
處理器
記憶體
典型的并發系統
并發/并行
單處理器
共享記憶體
OS核心/多線程程式
并發不并行
多處理器
并發、并行
不共享記憶體
分布式系統(消息通信)
多線程之間,寄存器組的值、堆棧(包括堆棧中的局部變量)是互相獨立的;代碼是共享的。
在C++中,可以使用pthread_create和pthread_join得到共享代碼、共享資料、獨立堆棧的多個線程。(will新開一個部落格寫)
Q1:每個線程的堆棧範圍和大小?
A1:每個線程有8MB的記憶體映射區域和前後各4KB的保護頁。
Q2:每個線程有8M的堆棧,那麼為什麼1000個線程沒有耗盡記憶體?
A2:因為雖然每個線程有8MB的記憶體區域,但是它們是虛拟記憶體,并且在沒有被使用的時候不會映射到實體記憶體上(Lazy allocate),是以實體記憶體的占用并沒有那麼多。
編譯器優化->順序的喪失:指令的執行不保證按照代碼書寫的順序發生;
中斷/并行->原子性的喪失:代碼的原子性随時被破壞;
亂序執行->可見性的喪失:執行過的指令可能在多處理器之間不可見。
從狀态機的理論去了解程式,程式的狀态(記憶體/寄存器的快照)可以看成有限狀态機的節點,程式的運作可以看成狀态轉換的過程。假如系統上有16MB的記憶體,即16*8Mb,那麼可以有2^(16*8M)種狀态。
大部分狀态有唯一的後續狀态,執行一條指令可以得到确定的結果。不确定的指令可能有多個後續狀态,例如執行rdrand指令(生成真随機數),會對rax指令賦予不同的值,是以可以帶給狀态機不确定性。
對于程式來說,不确定性的來源可能是:
(時間)rdtsc/rdtscp:擷取處理器的“時間戳”用于精确定時;
(機器狀态)rdrand:處理器自身提供的“真”随機數指令;
(系統調用)syscall:應用程式的最大不确定性來源,包括使用者的鍵入、磁盤檔案的讀取等。
在計算機硬體上的應用:高性能處理器實作,當狀态機的執行具有确定性的時候,A->B->C的狀态轉換可以優化為A->C。
在計算機系統上的應用:程式分析技術。靜态分析是根據程式代碼推導出狀态機的性質;動态分析是運作時觀測到狀态機的執行。
程式的執行是随着時間“前進”的(\(s_1\)->\(s_2\)->\(s_3\)->...),能否在時間上“後退”(Time-travel)?記錄所有的狀态\(s_i\),就能實作time-traveling。
如果記錄下所有的狀态,就可以回到任意一個狀态去檢視當時的資訊。但難點在于,上文讨論過,狀态的數量非常龐大,這樣的記錄非常耗費空間。已知每條指令隻會對狀态中很少一部分的寄存器/記憶體進行修改。
由此一個好主意是隻記錄初始狀态和每條指令前後狀态的diff。
gdb提供了這樣的time-travel debugging功能:
target record-full 開始記錄(需要程式開始執行);
record stop 結束記錄;
reverse-step/reverse-stepi “時間旅行調試”。
系統中有n個線程,線程之間是共享記憶體的,則并發程式的狀态s = (M, R1, R2, R3, ..., Rn)
并發系統執行指令的順序是不确定的,每個(M, R1), (M, R2), (M, R3), ...都可以看成是一個串行程式,在任意一個狀态,可以選擇任意一個線程執行一條指令。
即使每個線程都是确定的,在任意一個時刻,處理器可以選擇任意線程執行,此處帶有不确定性,是以即使沒有上述的程式三大不确定性來源,多線程程式也擁有天生的不确定性。
假如有n個線程,每個線程都執行m個線上程和時間上都獨一無二的操作,那麼從初始狀态到結束狀态(程式運作結束)是O(n^(mn)),這是一個非常大的數值。
狀态機是了解程式執行的重要工具。
程式是指令序列的靜态描述,高度概括、精簡,行為有時難以了解;
狀态機是所有動态行為的集合,将靜态時的分支、循環全部展開為了順序結構,行為明确、容易了解。
C++11 新标準中引入了五個頭檔案來支援多線程程式設計,它們分别是 <code><atomic>, <thread>, <mutex>, <condition_variable></code> 和 <code><future></code>。
<code><atomic></code>:該頭文主要聲明了兩個類, <code>std::atomic</code> 和 <code>std::atomic_flag</code>,另外還聲明了一套 C 風格的原子類型和與 C 相容的原子操作的函數。
<code><thread></code>:該頭檔案主要聲明了 <code>std::thread</code> 類,另外 <code>std::this_thread</code> 命名空間也在該頭檔案中。
<code><mutex></code>:該頭檔案主要聲明了與互斥量(Mutex)相關的類,包括 <code>std::mutex_*</code> 一系列類,<code>std::lock_guard</code>, <code>std::unique_lock</code>, 以及其他的類型和函數。
<code><condition_variable></code>:該頭檔案主要聲明了與條件變量相關的類,包括 <code>std::condition_variable</code> 和 <code>std::condition_variable_any</code>。
<code><future></code>:該頭檔案主要聲明了 <code>std::promise</code>, <code>std::package_task</code> 兩個 Provider 類,以及 <code>std::future</code> 和 <code>std::shared_future</code> 兩個 Future 類,另外還有一些與之相關的類型和函數,<code>std::async()</code> 函數就聲明在此頭檔案中。
使用示例:(編譯時需要加上-std=c++11 -pthread)
<thread>頭檔案的摘要如下,聲明了std::thraed線程類和std::swap輔助函數,以及命名空間std::this_thread。
std::thread類如下。