《線程管理:傳遞參數、確定線程數量、線程標識》

參考《c++ Concurrency In Action 》第二章做的筆記

目錄

  • 傳遞參數
  • 量產線程
  • 線程標識

傳遞參數

thread構造函數的附加參數會拷貝至新線程的內存空間中,即使函數中的采納數是引用類型,拷貝操作也會執行。如果我們期待傳入一個引用,必須使用std::ref將參數轉換成引用形式:

如下:

void update_weight(weight_id w,weight_data& data);	//1
void oops(weight_id w)
{weight_data data;//錯誤方式std::thread t(update_weight,w,data);//正確方式std::thread t(update_weight,w,std::ref(data));display_status();t.join();
}

這樣就能收到data的引用,而非data的拷貝副本。

std:bind的傳參機制相同,使用std::thread創建線程時,傳遞參數的過程如下:

  • std::thread構造函數傳參:一般實參會被拷貝至新線程的內存空間。具體拷貝的過程是由調用線程(主線程)在堆上創建并交由子線程管理,在子線程結束時同時被釋放。
  • 向線程函數傳參:由于std::thread對象里一般保存的是參數的副本,為了效率同時兼顧一些只移動類型的對象,所有的副本均被std::move到線程函數,即以右值的形式傳入。

示例:std::move轉移動態對象的所有權到線程中去:

void process_big_object(std::unique_ptr<big_object>);std::unique_ptr<big_object> p(new big_object);
p->prepare_data(47);
std::thread t(process_big_object,std::move(p));

在thread構造函數中執行move,big_object對象的所有權首先轉移到新創建線程的內部存儲中,之后再傳遞給process_big_object函數。

量產線程

void do_work(unsigned id);void f()
{std::vector<std::thread> threads;for(unsigned i = 0; i < 20; i++)threads.emplace_back(do_work,i);	//產生線程for(auto& entry : threads)				//對每個線程調用join()entry.join();
}

使用線程去分割一個算法的工作總量,所以在算法結束之前,所有線程必須結束。線程所做的工作都是獨立的,并且結果僅會受到共享數據的影響。如果f有返回值,在寫入返回值之前,程序會檢查使用共享數據的線程是否終止。

下面函數,會返回并發線程的數量

std::thread::hardware_concurrency()

下面展示并行版本的std::accumulate。代碼將整體工作拆分成小任務,交給每個線程去做,并設置最小任務數,避免產生太多的線程,程序會在操作數量為0時拋出異常。

template<typename Iterator,typename T>
struct accumulate_block
{void operator()(Iterator first,Iterator last,T& result){result = std::accumulate(first,last,result);}
};template<typename Iterator,typename T>
T parallel_accumulate(Iterator first,Iterator last,T init)
{unsigned long const length = std::distance(first,last);if(!length)		//1return init;unsigned long const min_per_thread = 25;unsigned long const max_threads = (length+min_per_thread-1)/min_per_thread;		//2unsigned long const hardware_threads = std::thread::hardware_concurrency();unsigned long const num_threads = 								//3std::min(hardware_threads != 0 ? hardware_threads : 2,max_threads);unsigned long const block_size = length / num_threads;			//4std::vector<T> results(num_threads);std::vector<std::thread> threads(num_threads - 1);				//5Iterator block_start = first;for(unsigned long i = 0; i < num_threads-1; ++i){Iterator block_end = block_start;std::advance(block_end,block_size);							//6threads[i] = std::thread(									//7accumulate_block<Iterator,T>(),block_start,block_end,std::ref(result[i]));block_start = block_end;									//8}accumulate_block<Iterator,T>(),block_start,last,results[num_threads-1]);				//9for(auto& entry : threads)entry.join();												//10return std::accumulate(results.begin(),results.end(),init);		//11		
}

函數解釋:

如果輸入范圍為空1,就會得到init值。如果范圍內的元素多于1個,需要用范圍內元素的總數量除以線程塊中最小任務數,從而確定啟動線程的最大數量。由于上下文切換可能會降低線程性能,所以計算最大線程數以及硬件支持線程數,選擇較小值作為啟動線程數量3。如果為0的話,選擇2替代。

每個線程中處理的元素數量,是范圍中元素的總量除以線程的個數得出的4。

既然確定了線程個數,創建一個std::vector<T>容器存放中間結果,并為線程創建一個std::vector<std::thread>容器。因為在啟動之前已經有了一個主線程,所以啟動線程數是num_threads-1。

使用循環啟動線程,block_end指向當前塊的末尾6,并啟動一個新線程為當前塊累加結果7.當迭代器指向當前塊的末尾時,啟動下一個塊8.

啟動所有縣城后,9中線程會處理最終塊的結果,累加最終塊結果后,等待std::for_each創建線程10.之后使用std::accumulate將所有結果進行累加11

線程標識

線程標識為std::thread::id類型,可以通過成員函數get_id()來獲取。如果thread對象沒有和任何執行線程相關聯,將返回一個默認構造值,表示“無線程”。

如果兩個線程id相等,說明是同一個線程,或者都是“無線程”。

std::thread::id實例常用作檢測線程是否需要進行一些操作,比如,當用線程來分割一項工作,主線程可能要做一些與其他線程不同的工作,啟動其他線程前,可以通過get_id得到自己線程id,每個線程都檢查一下,其擁有線程id是否與初始線程id相同。

std::thread::id master_thread;
void some_core_part_of_algorithm()
{if(std::this_thread::get_id() == master_thread)do_master_thread_work();elsedo_common_work();
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/377038.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/377038.shtml
英文地址,請注明出處:http://en.pswp.cn/news/377038.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

手把手玩轉win8開發系列課程(14)

這節的議程就是——添加appbar appbar是出現在哪兒了&#xff0c;出現在屏幕的底部。他能使用戶能用手勢或者使用鼠標操作程序。metro UI 重點是在主要的控件使用許多控件&#xff0c;使其用戶使用win8電腦更加的方便。而appBar使其用戶體驗更好。在這節中&#xff0c;我將告訴…

No identities are available for signing 的解決辦法

今天重新上傳做好的app提交到app store&#xff0c;結果就出現標題上的錯誤。“No identities are available for signing”。 以后碰到這樣的問題按照下面幾個步驟來做&#xff1a; 進入Distribution -----下載發布證書 -----雙擊安裝-----重啟Xcode就能上傳了 其他細節 如果再…

半連接反連接

半連接&反連接 1. 半連接 半連接返回左表中與右表至少匹配一次的數據行&#xff0c;通常體現為 EXISTS 或者 IN 子查詢。左表驅動右表。只返回左表的數據&#xff0c;右表作為篩選條件。 可以用 EXISTS、 IN 或者 ANY 舉例&#xff1a;表t1和表t2做半連接&#xff0c;t…

匿名方法和Lambda表達式

出于MVVM學習的需要&#xff0c;復習下匿名方法和Lambda表達式&#xff0c;因為之前用的也比較少&#xff0c;所以用的也不是很熟練&#xff0c;Baidu下相關的知識&#xff0c;寫了這個Demo&#xff0c;目標是用簡單的方法展示這個怎么用。 這里偏重的和LINQ中的Lambda表達式 …

爛橘子

Problem Statement: 問題陳述&#xff1a; Given a matrix of dimension r*c where each cell in the matrix can have values 0, 1 or 2 which has the following meaning: 給定尺寸r * C的矩陣&#xff0c;其中矩陣中的每個單元可以具有其具有以下含義的值0&#xff0c;1或2…

android junit 測試程序

http://blog.csdn.net/to_cm/article/details/5704783 Assert.assertEquals(2, t); 斷言轉載于:https://www.cnblogs.com/wjw334/p/3714120.html

MySQL 8.0.22執行器源碼分析HashJoin —— BuildHashTable函數細節步驟

BuildHashTable函數細節步驟 該函數位置處于hash_join_iterator.cc 403 ~ 560行 step1&#xff1a;如果被驅動表迭代器沒有更多的行數&#xff0c;更新m_state為EOR&#xff0c;然后返回false&#xff0c;表明創建hash表失敗 if (!m_build_iterator_has_more_rows) {m_state…

《那些年啊,那些事——一個程序員的奮斗史》——125

距離離職交接的一個月時間還剩幾天&#xff0c;本來應該是平淡無事的&#xff0c;卻沒想到最后還是波瀾四起。昨天下班前&#xff0c;公司突然停了電。這本是件普通得不能再普通的事情&#xff0c;可沒想到過了一會來電了&#xff0c;或許是波峰電壓太大&#xff0c;或許是穩壓…

python中的元類_Python中的元類

python中的元類Python元類 (Python metaclass) A metaclass is the class of a class. A class defines how an instance of a class i.e.; an object behaves whilst a metaclass defines how a class behaves. A class is an instance of a metaclass. 元類是類的類。 一個類…

MySQL 8.0.22執行器源碼分析HashJoin —— 一些初始化函數的細節步驟

目錄InitRowBuffer&#xff08;101行~126行&#xff09;InitProbeIterator&#xff08;142行~153行&#xff09;*HashJoinIterator* 的Init&#xff08;155行~240行&#xff09;InitializeChunkFiles&#xff08;364行~401行&#xff09;InitWritingToProbeRowSavingFile&#…

c語言的宏定義學習筆記

宏定義 在預處理之前&#xff0c;c預處理器會對代碼進行翻譯&#xff0c;譬如用blank替換注釋&#xff0c;去掉多余的空格&#xff0c;刪除末尾的\來拼接行等。 例如&#xff1a; int /*注釋*/ x; 會被翻譯成 int x; printf("this is a s\ entence."); 會被翻譯成 pr…

攝氏溫度轉換華氏溫度_什么是攝氏溫度?

攝氏溫度轉換華氏溫度攝氏溫度 (Celsius) Celsius is a temperature measuring scale which as a SI unit derived from the seven base units stated and described by the International System of Units (SI). 攝氏溫度是一種溫度測量刻度&#xff0c;它是由國際單位制(SI)所…

別人的算法學習之路

http://www.cnblogs.com/figure9/p/3708351.html 我的算法學習之路 關于 嚴格來說&#xff0c;本文題目應該是我的數據結構和算法學習之路&#xff0c;但這個寫法實在太繞口——況且CS中的算法往往暗指數據結構和算法&#xff08;例如算法導論指的實際上是數據結構和算法導論&a…

git config命令使用第二篇——section操作,多個key值操作,使用正則

接上一篇&#xff0c;git config命令使用第一篇——介紹&#xff0c;基本操作&#xff0c;增刪改查:http://blog.csdn.net/hutaoer06051/article/details/8275069 1. 刪除一個section 命令參數 --remove-section 格式&#xff1a;git config [--local|--global|--system] --rem…

MySQL面試準備——64頁pdf

本筆記為以前整理的零碎的關于Mysql的知識點&#xff0c;有深入源碼的也有淺層的八股。已經被我整理成了一個pdf。 實習崗位正好也是和數據庫內核有關的&#xff0c;之后應該還會更新。做個整理&#xff0c;方便秋招的時候快速回顧吧。 鏈接&#xff1a;鏈接 提取碼&#xff1a…

python點圖_Python | 點圖

python點圖The dot plot is a type of data representation in which each data-point in the figure is represented as a dot. Dot plot underlies discrete functions unlike a continuous function in a line plot. Each value could be correlated but cannot be connecte…

SAP-MM:發票、貸方憑證、事后借記、后續貸記

發票和事后借記 相同點&#xff1a;增加對供應商的應付款 不同點&#xff1a;針對同一訂單收貨&#xff0c;發票要先于事后借記&#xff08;事后借記是對供應商后期發票金額的補充&#xff09;&#xff1b;發票和金額、訂單數量有關系&#xff0c;而事后借記只是訂單金額調整的…

Dijkstra for MapReduce (1)

<math xmlns"http://www.w3.org/1998/Math/MathML"><mi>x</mi><mo>,</mo><mi>y</mi><mo>&#x2208;<!-- ∈ --></mo><mi>X</mi> </math> 準備研究一下Dijkstra最短路徑算法Hadoop上…

sql的外鍵約束和主鍵約束_SQL約束

sql的外鍵約束和主鍵約束SQL | 約束條件 (SQL | Constraints) Constraints are the guidelines implemented on the information sections of a table. These are utilized to restrict the kind of information that can go into a table. This guarantees the precision and …

nios pio interrupt 的使能

關于nios 中的中斷&#xff0c;因為要16c550中需要nios的中斷環境去測試&#xff0c;所以就用到了中斷。 硬件&#xff1a;在nios中添加硬件PIO,但是要使能中斷功能。如下圖所示&#xff1a; 系統列化&#xff0c;PIO的連接就不說了。但是要注意兩地方&#xff1a;edge type&am…