c++14的新的多執行緒架構非常簡單易學,如果你對c或者c++很熟悉,那麼本文非常適合你。作者用c++14作為基準參考,但是所介紹的東西在c++17中也依然適用。本文只介紹基本的架構,在讀完本文後你應該也可以自己編寫自己的多執行緒程式。
建立執行緒有以下幾種方式:
1.使用函式指標
2.使用仿函式
3.使用lambda表示式
這些方式都比較類似,只有部分差別,我將在下面具體講述每一種方式和他們的區別。
來看看下面這個函式,其引數包括乙個vector的引用 v ,乙個輸出結果的引用acm,還有兩個v的索引。這個函式會將v的beginindex和endindex之間的元素累加起來。
1void accumulator_function2(const std::vector &v, unsigned long
long &acm,
2 unsigned int beginindex, unsigned int
endindex)
39 }
現在如果我們想將vector分為兩個部分,並在單獨的執行緒t1和t2中分別計算各部分的總和的話,我們可以這麼寫:
1//pointer to function
2
1.std::thread這個呼叫建立了乙個新的執行緒。其第乙個引數是函式指標 accumulator_function2 ,因此每個執行緒都會去執行這個函式。
2.剩下的我們傳給std::thread的建構函式的引數,都是我們需要去傳給accumulator_function2的引數。
3.重點:傳遞給accumulator_function2的引數預設情況下都是值傳遞的,除非你用std::ref把他包起來。所以我們這裡使用了std::ref來包住v、acm1、acm2。
4.使用std::thread建立的執行緒是沒有返回值的,所以如果你想從執行緒中返回些什麼,請使用引用將你想返回的值作為乙個傳入引數。這裡的例子就是acm1和acm2。
5.每個執行緒一旦建立就立即執行了。
6.我們使用join()函式來等待執行緒執行完畢。
你也可以使用偽函式來做同樣的事情,下面是例子:
1class
caccumulatorfunctor3212
}13 unsigned long
long
_acm;
14 };
那麼建立執行緒的方式變成下面這樣:
1//creating thread using functor
2
偽函式的使用方式大部分地方都和函式指標很像,除了:
1.第乙個引數變成了偽函式物件。
2.我們不再需要使用引用來獲取返回值了,我們可以將返回值作為偽函式物件的乙個成員變數來儲存。這裡的例子就是_acm。
作為第三種選擇,我們可以在每個執行緒的建構函式中使用lambda表示式來定義我們想做的事,如下:
19});
10 std::thread t2([&acm2, &v]
15});
16t1.join();
17t2.join();
1819 std::cout << "
acm1:
"<< acm1 <20 std::cout << "
acm2:
"<< acm2 <21 std::cout << "
acm1 + acm2:
"<< acm1 + acm2 <22 }
同樣,大多數地方都和函式指標的方式很類似,除了:
1.作為傳參的替代方式,我們可以使用lambda表示式的捕獲(capture)方式來處理引數傳遞
除了std::thread,我們還可以使用 tasks.
tasks和std::thread工作的方式非常相似,只有乙個最主要的不同:tasks可以返回乙個值。因此,你可以暫存這個返回值來作為這個執行緒的更抽象的定義方式,並在你真的需要返回的結果的時候來從這個返回值中拿到資料。
下面就是使用tasks的例子:
1 #include 2//tasks, future, and promises311
12return
acm;
13};
1415 auto t1 = std::async(f1, std::ref
(v),
160, v.size() / 2
);17 auto t2 = std::async(f1, std::ref
(v),
18 v.size() / 2
, v.size());
1920
//you can do other things here!
21 unsigned long
long acm1 = t1.get
();22 unsigned long
long acm2 = t2.get
();23
24 std::cout << "
acm1:
"<< acm1 <25 std::cout << "
acm2:
"<< acm2 <26 std::cout << "
acm1 + acm2:
"<< acm1 + acm2 <27 }
1.tasks使用std::async建立
2.std::async的返回值是乙個叫std::future的型別。別被他的名字唬到,他的意思是t1和t2的值會在未來被真正的賦值。我們通過呼叫t1.get()來獲得他的真正的返回值。
3.如果future的返回值還沒有準備好(任務還沒有計算完成),那麼呼叫get()的主線程會被卡住,直到準備好了返回值(和join()的行為一樣)。
4.注意,我們傳遞給std::async的函式(實際上是lambda表示式)是有返回值的,這個返回值用過乙個叫做std::promise的型別來傳遞。大多數情況下你不需要了解任何promise的細節,c++在幕後可以處理好這些事情。
5.預設的情況下,tasks也會在建立之後立刻執行(有辦法來修改這個行為,但是本文沒有涉及)。
建立執行緒很簡單,你可以通過函式指標、偽函式、lambda表示式的方式來建立std::thread,也可以使用std::async的方式來獲得乙個std::future型別的返回值。std::async也同樣可以使用函式指標、偽函式、lambda表示式來建立
(未完待續)
C 類模板5分鐘入門
參考自 c 除了支援函式模板,還支援類模板 class template 函式模板中定義的型別引數可以用在函式宣告和函式定義中,類模板中定義的型別引數可以用在類宣告和類實現中。類模板的目的同樣是將資料的型別引數化。宣告類模板的語法為 templateclass 類名 類模板和函式模板都是以 temp...
C 命名空間,5分鐘詳解
在c 中,名稱 name 可以是符號常量 變數 函式 結構 列舉 類和物件等等。工程越大,名稱互相衝突性的可能性越大。另外使用多個廠商的類庫時,也可能導致名稱衝突。為了避免,在大規模程式的設計中,以及在程式設計師使用各種各樣的c 庫時,這些識別符號的命名發生衝突,標準c 引入關鍵字namespace...
《轉》C語言指標5分鐘教程
什麼是指標?什麼是記憶體位址?什麼叫做指標的取值?指標是乙個儲存計算機記憶體位址的變數。在這份教程裡 引用 表示計算機記憶體位址。從指標指向的記憶體讀取資料稱作指標的取值。指標可以指向某些具體型別的變數位址,例如int long和double。指標也可以是void型別 null指標和未初始化指標。本...