5分鐘速成C 14多執行緒程式設計

2022-08-09 10:57:13 字數 3375 閱讀 7498

c++14的新的多執行緒架構非常簡單易學,如果你對c或者c++很熟悉,那麼本文非常適合你。作者用c++14作為基準參考,但是所介紹的東西在c++17中也依然適用。本文只介紹基本的架構,在讀完本文後你應該也可以自己編寫自己的多執行緒程式。

建立執行緒有以下幾種方式:

1.使用函式指標

2.使用仿函式

3.使用lambda表示式

這些方式都比較類似,只有部分差別,我將在下面具體講述每一種方式和他們的區別。

來看看下面這個函式,其引數包括乙個vector的引用 v ,乙個輸出結果的引用acm,還有兩個v的索引。這個函式會將v的beginindex和endindex之間的元素累加起來。

1

void 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()函式來等待執行緒執行完畢。

你也可以使用偽函式來做同樣的事情,下面是例子:

1

class

caccumulatorfunctor3212

}13 unsigned long

long

_acm;

14 };

那麼建立執行緒的方式變成下面這樣:

1

//creating thread using functor

2

偽函式的使用方式大部分地方都和函式指標很像,除了:

1.第乙個引數變成了偽函式物件。

2.我們不再需要使用引用來獲取返回值了,我們可以將返回值作為偽函式物件的乙個成員變數來儲存。這裡的例子就是_acm。

作為第三種選擇,我們可以在每個執行緒的建構函式中使用lambda表示式來定義我們想做的事,如下:

1

9});

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指標和未初始化指標。本...