C++11標准在標准庫中為多線程提供了組件。
並發:
並發指的是兩個或多個獨立的活動在同一時段內發生。同一時間段內可以交替處理多個操作。一個CPU交替處理多個任務,存在競爭關系,在邏輯上表現為一個時段內同時處理多個任務。
並行:
並行就是同時執行,計算機在同一時刻,在某個時間點上處理兩個或以上的操作。判斷一個程序是否並行執行,只需要看某個時刻上是否多兩個或以上的工作單位在運行。一個程序如果是單線程的,那么它無法並行地運行。利用多線程與多進程可以使得計算機並行地處理程序(當然 ,前提是該計算機有多個處理核心)。在物理上表現為一個時段內同時處理多個任務。
並發重點指的是程序的設計結構,而並行指的是程序運行的狀態。並發編程,是一種將一個程序分解成小片段獨立執行的程序設計方法。
並發的基本方式途徑
多線程與多進程是並發的兩種途徑。
多進程並發
多個進程獨立地運行,它們之間通過進程間常規的通信渠道傳遞訊息(信號,套接字,文件,管道等),這種進程間通信不是設置復雜就是速度慢,這是因為為了避免一個進程去修改另一個進程,操作系統在進程間提供了一定的保護措施,當然,這也使得編寫安全的並發代碼更容易。
運行多個進程也需要固定的開銷:進程的啟動時間,進程管理的資源消耗。
多線程並發
在當個進程中運行多個線程也可以並發。線程就像輕量級的進程,每個線程相互獨立運行,但它們共享地址空間,所有線程訪問到的大部分數據如指針、對象引用或其他數據可以在線程之間進行傳遞,它們都可以訪問全局變量。線程之間通常共享內存,但這種共享通常難以建立且難以管理,缺少線程間數據的保護。因此,在多線程編程中,我們必須確保每個線程鎖訪問到的數據是一致的。
C++中的並發與多線程
C++標准並沒有提供對多進程並發的原生支持,所以C++的多進程並發要靠其他API——這需要依賴相關平台。
C++11 標准提供了一個新的線程庫,內容包括了管理線程、保護共享數據、線程間的同步操作、低級原子操作等各種類。標准極大地提高了程序的可移植性,以前的多線程依賴於具體的平台,而現在有了統一的接口進行實現。
C++11 新標准中引入了幾個頭文件來支持多線程編程:
< thread > :包含std::thread類以及std::this_thread命名空間。管理線程的函數和類在其中聲明。
< atomic > :包含std::atomic和std::atomic_flag類,以及一套C風格的原子類型和與C兼容的原子操作的函數。
< mutex > :包含了與互斥量相關的類以及其他類型和函數。
< future > :包含兩個Provider類(std::promise和std::package_task)和兩個Future類(std::future和std::shared_future)以及相關的類型和函數。
< condition_variable > :包含與條件變量相關的類,包括std::condition_variable和std::condition_variable_any。
開線程
單線程時:
1 # include<iostream> 2 using namespace std; 3 int main() 4 { 5 cout<<"hello world"<<endl; 6 }
在這里,進行由一個線程組成,該線程的初始函數是main。我們啟動第二個線程來打印hello world:
1 # include<iostream> 2 # include<thread> 3 using namespace std; 4 void hello() 5 { 6 cout<<"hello world"<<endl; 7 } 8 int main() 9 { 10 thread t (hello); 11 t.join(); 12 }
每個線程都必須有一個初始函數,新線程的執行開始於初始函數。對於第一段程序來說,它的初始函數是main,對於我們新創建的線程,可以在std::thread()對象的構造函數中指定。在第二段程序里,程序由兩個線程組成:初始線程始於main,新線程始於hello。這里將新線程t的初始函數指定為hello。
新線程啟動之后會與初始進程一並運行,初始線程可以等待或不等待新進程的運行結束——如果需要等待線程,則新線程實例需要使用join(),否則可以使用detach()。如果不等待新線程,則初始線程自顧自地運行到main()結束。