日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

学习英特尔线程构建模块开源2.1库

發布時間:2023/12/20 编程问答 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 学习英特尔线程构建模块开源2.1库 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

并行編程是未來,但是您如何才能有效利用多核CPU的高性能并行編程呢? 當然,也可以選擇使用諸如POSIX線程之類的線程庫,但是最初是出于C語言引入POSIX線程框架的。 這也是一種太底層的方法,例如,您無權訪問任何并發容器,也沒有任何可使用的并發算法。 在這一點上,英特爾推出了英特爾?線程構建塊(Intel TBB),這是一種基于C++的并行編程框架,具有許多有趣的功能,并且比線程具有更高的抽象水平。

常用縮略語
  • POSIX: UNIX的便攜式操作系統接口

下載和安裝Intel TBB并不需要什么特別的事情:提取的目錄層次結構讓人聯想到帶有include,bin,lib和doc文件夾的UNIX?系統。 出于本文的目的,我選擇了tbb30_20110427oss穩定版本。

英特爾TBB入門

英特爾TBB有很多工作要做。 以下是一些有趣的入門知識:

  • 您可以在任務中擁有更高級別的抽象,而不是線程。 英特爾聲稱,在Linux?系統上,啟動和終止任務比啟動和停止線程快18倍。
  • 英特爾TBB帶有任務計劃程序,該任務計劃程序可以有效處理多個邏輯和物理內核之間的負載平衡。 Intel TBB中的默認任務調度策略與大多數線程調度程序具有的循環策略不同。
  • 英特爾TBB提供現成的貨架線程安全的容器,如可用性concurrent_vector和concurrent_queue 。
  • 可以使用諸如parallel_for和parallel_reduce類的通用并行算法。
  • 模板類atomic提供了無鎖 (也稱為無互斥 )并發編程支持。 這種支持使Intel TBB適用于高性能應用程序,因為Intel TBB可以處理互斥鎖。
  • 全部都是C++ ! 由于沒有花哨的擴展名或宏,英特爾?TBB仍停留在該語言之內,從而大量使用了模板。

英特爾TBB確實有很多先決條件。 在開始之前,您應該具備:

  • C++模板以及對標準模板庫(STL)的一些理解。
  • 線程知識-POSIX線程或Windows?線程。

盡管不是必需的,但C++0x lambda函數在Intel TBB中找到了相當的用法。

英特爾TBB的討論始于創建和處理任務和同步原語(mutex),然后使用并發容器和并行算法。 它以使用原子模板的無鎖編程結束。

您好,World with Intel TBB任務

英特爾TBB基于任務的概念。 您定義自己的任務,這些任務派生自tbb / task.h中聲明的tbb::task 。 要求用戶在其代碼中覆蓋純虛擬方法task* task::execute ( ) 。 以下是每個Intel TBB任務的一些屬性:

  • 當Intel TBB任務計劃程序選擇運行某些任務時,將調用任務的execute方法。 那是切入點。
  • execute方法可以返回task* ,它告訴調度程序下一個要運行的任務。 如果返回NULL,則調度程序可以自由選擇下一個任務。
  • task::~task( )是虛擬的,并且用戶任務分配的任何資源都必須在此析構函數中釋放。
  • 通過調用task::allocate_root( ) 。
  • 主任務通過調用task::spawn_root_and_wait(task)來運行任務以完成task::spawn_root_and_wait(task) 。

下面的清單1顯示了第一個任務及其調用方式:

清單1.創建第一個英特爾TBB任務
#include "tbb/tbb.h" #include <iostream> using namespace tbb; using namespace std;class first_task : public task { public: task* execute( ) { cout << "Hello World!\n";return NULL;} };int main( ) { task_scheduler_init init(task_scheduler_init::automatic);first_task& f1 = *new(tbb::task::allocate_root()) first_task( );tbb::task::spawn_root_and_wait(f1); }

要運行Intel TBB程序,必須正確初始化任務計劃程序。 清單1中調度程序的參數是自動的,它使調度程序可以自己決定線程數。 當然,如果要控制產生的最大線程數,則可以覆蓋此行為。 但是在生產代碼中,除非您真的知道自己在做什么,否則最好將確定最佳線程數的工作留給調度程序。

現在您已經創建了第一個任務,讓清單1中的first_task產生一些子任務。 下面的清單2引入了一些新概念:

  • 英特爾TBB提供了一個名為task_list的容器,該容器旨在用作任務的集合。
  • 每個父任務都使用allocate_child函數調用創建一個子任務。
  • 在任務產生任何子任務之前,它必須調用set_ref_count 。 否則會導致未定義的行為。 如果要生成子任務,然后等待它們完成,則count必須等于子任務的數量+ 1; 否則, count應等于子任務數。 不久之后會更多。
  • 對spawn_and_wait_for_all的調用如其名稱所示:產生子任務并等待所有操作完成。

這是代碼:

清單2.創建多個子任務
#include "tbb/tbb.h" #include <iostream> using namespace tbb; using namespace std;class first_task : public task { public: task* execute( ) { cout << "Hello World!\n";task_list list1; list1.push_back( *new( allocate_child() ) first_task( ) );list1. push_back( *new( allocate_child() ) first_task( ) );set_ref_count(3); // 2 (1 per child task) + 1 (for the wait) spawn_and_wait_for_all(list1);return NULL;} };int main( ) { first_task& f1 = *new(tbb::task::allocate_root()) first_task( );tbb::task::spawn_root_and_wait(f1); }

那么,為什么英特爾TBB要求顯式設置set_ref_count ? 該文檔說,這主要是出于性能方面的考慮。 生成子代之前,必須始終為任務設置引用計數。 請參閱相關信息的鏈接,更多的細節。

您也可以創建任務組。 以下代碼創建一個任務組,該任務組產生兩個任務并等待它們完成。 task_group的run方法具有以下簽名:

template<typename Func> void run( const Func& f )

run方法產生一個可計算f( )但不會阻塞調用任務的任務,因此控件會立即返回。 為了等待子任務完成,調用任務調用wait (請參見下面的清單3 )。

清單3.創建一個task_group
#include "tbb/tbb.h" #include <iostream> using namespace tbb; using namespace std;class say_hello( ) { const char* message;public: say_hello(const char* str) : message(str) { }void operator( ) ( ) const { cout << message << endl;} };int main( ) { task_group tg;tg.run(say_hello("child 1")); // spawn task and returntg.run(say_hello("child 2")); // spawn another task and return tg.wait( ); // wait for tasks to complete }

請注意task_group的語法簡單性-直接處理任務時不需要進行內存分配等調用,并且您無需對ref計數做任何事情。 這就是任務。 英特爾TBB任務可以完成數百種事情。 請確保深入了解Intel TBB文檔以獲取更多詳細信息。 讓我們繼續并發容器。

并發容器:矢量

現在,讓我們集中討論Intel TBB的并發容器之一: concurrent_vector 。 此容器在標頭tbb / concurrent_vector.h中聲明,并且基本接口類似于STL向量:

template<typename T, class A = cache_aligned_allocator<T> > class concurrent_vector;

可以將多個控制線程安全地添加到向量中,而無需任何顯式鎖定。 從英特爾TBB手動意譯, concurrent_vector具有以下特性:

  • 它提供對元素的隨機訪問; 索引從位置0開始。
  • 安全并發增加大小是可能的,并且可以同時添加多個線程。
  • 添加新元素不會使現有索引或迭代器無效。

但是,并發是有代價的。 與STL不同,在STL中,添加新元素涉及數據的移動,而concurrent_vector數據不移動。 而是,容器維護一系列連續的內存段。 顯然,這增加了容器開銷。

對于同時添加向量,可以使用三種方法:

  • push_back在向量的末尾附加一個元素。
  • grow_by(N) -append N型的連續元素T到concurrent_vector和迭代器返回到第一所附元件。 每個元素都用T ( )初始化。
  • grow_to_at_least(N) -Grow載體以大小為N,如果向量的當前大小小于N。

您可以按如下所示將字符串附加到concurrent_vector :

void append( concurrent_vector<char>& cv, const char* str1 ) { size_t count = strlen(str1)+1; std::copy( str1, str1+count, cv.grow_by(count) ); }

借助英特爾?TBB立即使用并行算法

關于Intel TBB的最好的事情之一是,它使您可以自動并行化部分源代碼,而不必費心創建和維護線程。 最常見的并行算法是parallel_for 。 考慮以下示例:

void serial_only (int* array, int size) { for (int count = 0; count < size; ++count)apply_transformation (array [count]); }

現在,如果上一apply_transformation中的apply_transformation例程沒有做任何奇怪的事情,例如僅對單個數組元素進行了一些轉換,那么您就無法阻止將負載分配給多個CPU內核。 您需要英特爾TBB庫中的兩個類才能入門: blocked_range (來自tbb / blocked_range.h)和parallel_for (來自tbb / parallel_for.h)。

blocked_range類旨在創建一個向迭代器提供parallel_for的對象,因此您需要創建諸如blocked_range (0, size) ,并將其作為輸入傳遞給parallel_for 。 parallel_for需要的第二個也是最后一個參數是具有清單4中的要求的類(從parallel_for.h標頭粘貼)。

清單4. parallel_for的第二個參數的要求
/** \page parallel_for_body_req Requirements on parallel_for bodyClass \c Body implementing the concept of parallel_for body must define:- \code Body::Body( const Body& ); \endcode Copy constructor- \code Body::~Body(); \endcode Destructor- \code void Body::operator()( Range& r ) const; \endcode Function call operator applying the body to range \c r. **/

該代碼告訴您,您需要使用operator ( )創建自己的類,并使用blocked_range作為參數,并在operator ( )的方法定義內對您先前創建的serial for循環進行編碼。 復制構造函數和析構函數應該是公共的,并且您讓編譯器為您提供默認值。 下面的清單5顯示了代碼。

清單5.為parallel_for創建第二個參數
#include "tbb/blocked_range.h" using namespace tbb;class apply_transform{ int* array; public: apply_transform (int* a): array(a) {} void operator()( const blocked_range& r ) const { for (int i=r.begin(); i!=r.end(); i++ ){ apply_transformation(array[i]); } } };

現在您已經成功創建了第二個對象,您只需調用parallel_for ,如清單6所示。

清單6.使用parallel_for并行化循環
#include "tbb/blocked_range.h" #include "tbb/parallel_for.h" using namespace tbb;void do_parallel_the_tbb_way(int *array, int size) { parallel_for (blocked_range(0, size), apply_transform(array)); }

英特爾TBB中的其他并行算法

英特爾TBB提供了很多并行算法,例如parallel_reduce (在tbb / parallel_reduce.h中聲明)。 假設您要匯總所有元素,而不是對每個單獨的數組元素應用轉換。 這是序列號:

void serial_only (int* array, int size) { int sum = 0;for (int count = 0; count < size; ++count)sum += array [count]; return sum; }

從概念上講,在并行上下文中運行此代碼將意味著每個控制線程都應匯總數組的某些部分,并且必須在某處存在join方法來匯總部分求和。 下面的清單7顯示了Intel TBB代碼。

清單7.串行for循環求和數組元素
#include "tbb/blocked_range.h" #include "tbb/parallel_reduce.h" using namespace tbb;float sum_with_parallel_reduce(int*array, int size) {summation_helper helper (array); parallel_reduce (blocked_range<int> (0, size, 5), helper);return helper.sum; }

在將每個線程的數組拆分為子數組時,您需要保持一定的粒度(例如,每個線程負責對N個元素求和,其中N既不太大也不不太小)。 那是blocked_range的第三個參數。 英特爾TBB要求summation_helper類滿足兩個條件:它必須具有一個名為join的方法以添加部分和和以及一個帶有特殊參數的構造函數(稱為splitting構造函數 )。 清單8提供了代碼:

清單8.使用join方法創建summation_helper類并拆分構造函數
class summation_helper {int* partial_array; public:int sum;void operator( )( const blocked_range<int>& r ) {for( int count=r.begin(); count!=r.end( ); ++count)sum += partial_array [count];}summation_helper (summation_helper & x, split): partial_array (x. partial_array), sum (0) {}summation_helper (int* array): partial_array (array), sum (0){}void join( const summation_helper & temp ) { sum += temp.sum; // required method } };

這就是將會發生的事情。 Intel TBB調用splitting構造函數(稱為split的第二個參數是Intel TBB所需的虛擬參數),并且部分數組由一定數量的元素填充(該數量是blocked_range定義的粒度的函數)。 當子數組上的求和完成時, join方法將添加部分結果。 有點復雜? 乍看起來也許; 只需記住您需要三個方法: operator( )添加數組范圍, join添加以添加部分結果,以及split構造函數以啟動新的工作線程。

英特爾TBB還有其他幾種有用的算法, parallel_sort是最有用的算法之一。 請參閱英特爾TBB參考手冊(見相關信息 )了解詳情。

使用Intel TBB進行無鎖編程

在多線程編程期間經常出現的一個問題是,互斥鎖的鎖定和解鎖浪費了CPU周期數。 如果您來自POSIX線程背景,英特爾TBB的atomic模板將使您感到驚訝。 它是互斥鎖的替代方法,速度要快得多,并且您可以放心地取消對鎖定和解鎖代碼的需求。 atomic是所有編碼難題的靈丹妙藥嗎? 否。它的使用受到嚴格限制。 但是,如果您要創建高性能代碼,這將非常有效。 聲明整數為atomic類型的方法如下:

#include "tbb/atomic.h" using namespace tbb;atomic<int> count; atomic<float* > pointer_to_float;

現在,假設多個控制線程正在訪問較早版本的變量計數。 通常,您希望在寫入過程中使用互斥量來保護計數; 但是, atomic<int>不再需atomic<int> 。 看一下清單9 。

清單9.原子fetch_and_add不需要鎖定
// writing with mutex, count is declared as int count; {// … codepthread_mutex_lock (&lock);count += 1000; pthread_mutex_unlock (&lock);// … code continues }// writing without mutex, count declared as atomic<int> count; {// … codecount.fetch_and_add (1000); // no explicit locking/unlocking// … code continues }

代替+= ,可以使用atomic<T>類的fetch_and_add方法。 不,它在內部不使用任何互斥鎖作為fetch_and_add方法的一部分。 當執行fetch_and_add ,它的作用是立即加1000以立即count -所有線程一次都可以看到count的更新值,或者所有線程都可以繼續看到舊值。 這就是為什么count被聲明為atomic變量:對操作count是原子,并且不能按照進程或線程調度的反復無常而中斷。 無論如何調度線程,都無法在不同線程中count不同的值。 有關無鎖編程的深入討論,請參閱參考資料 。

atomic<T>類具有以下五個基本操作:

y = x; // atomic read x = b; // atomic write x.fetch_and_store(y); // y = x and return the old value of x x.fetch_and_add(y); // x += y and return the old value of x x.compare_and_swap(y, z); // if (x == z) x = y; in either case, return old value of x

另外,為方便起見,支持運算符+= , -= , ++和-- ,但它們都在fetch_and_add之上fetch_and_add 。 如tbb / atomic.h所示,這是定義運算符的方式( 清單10 )。

清單10.使用fetch_and_add定義的運算符++,-,+ =和-=
value_type operator+=( D addend ) {return fetch_and_add(addend)+addend; }value_type operator-=( D addend ) {// Additive inverse of addend computed using binary minus,// instead of unary minus, for sake of avoiding compiler warnings.return operator+=(D(0)-addend); }value_type operator++() {return fetch_and_add(1)+1; }value_type operator--() {return fetch_and_add(__TBB_MINUS_ONE(D))-1; }value_type operator++(int) {return fetch_and_add(1);}value_type operator--(int) {return fetch_and_add(__TBB_MINUS_ONE(D));}

請注意, atomic<T>中的類型T只能是整數類型,枚舉類型或指針類型。

結論

不可能在一篇文章中公正地描述一個具有英特爾TBB規模的圖書館。 確實,英特爾網站上有數十篇文章重點介紹了英特爾TBB的多個方面。 取而代之的是,本文試圖深入了解Intel TBB隨附的一些引人注目的功能-任務,并發容器,算法以及創建無鎖代碼的方法。 希望本文的介紹激發了您的興趣,英特爾TBB將獲得另一個熱情的用戶—就像作者本人一樣。


翻譯自: https://www.ibm.com/developerworks/aix/library/au-intelthreadbuilding/index.html

總結

以上是生活随笔為你收集整理的学习英特尔线程构建模块开源2.1库的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 求av网址| 制服丝袜一区在线 | 欧美性猛交bbbbb精品 | 法国极品成人h版 | 射婷婷 | 一线毛片 | 生活片一级片 | 美女视频黄a视频全免费观看 | 日本激情网站 | 日本少妇性高潮 | 日本黄色a级片 | 一级全黄男女免费大片 | 亚洲欧美日本韩国 | 亚洲网站免费观看 | 亚洲男性天堂 | 91涩涩涩| 手机电影在线观看 | 日本爽爽| 91精品亚洲一区 | 国产美女福利 | 日韩不卡免费视频 | 日韩手机视频 | 一区二区三区四区精品 | 欧美视频一二三区 | 97免费人妻无码视频 | 欧美日韩三级在线观看 | 3d动漫精品啪啪一区二区下载 | 亚洲五码av | 精品欧美一区二区三区免费观看 | 欧美顶级少妇做爰hd | 国产免费一区二区视频 | xxxx视频在线观看 | av免费国产 | 久久噜噜噜精品国产亚洲综合 | 伊人网伊人影院 | www.成人免费 | 日本公妇乱淫免费视频一区三区 | 国产精品久久久久精 | 久久99国产综合精品免费 | 亚洲综合一区二区三区 | 日韩精品福利在线 | 日韩av综合在线 | 黑人巨大猛烈捣出白浆 | 日韩视频免费播放 | 在线a视频 | 黄色av免费在线观看 | 两个人做羞羞的视频 | 亚洲欧美动漫 | 成年人免费看视频 | 女女百合高h喷汁呻吟玩具 www.亚洲一区 | 日韩一级免费 | 午夜一区二区三区在线 | 狠狠干天天射 | 久草午夜| 久操视频精品 | 国产女主播自拍 | 欧洲免费av | 亚洲AV无码精品黑人黑人 | 国产免费一区二区 | 国产高清在线 | 女性裸体视频网站 | 一级免费毛片 | 欧美成人女星 | 亚洲av综合永久无码精品天堂 | 国产伦精品一区二区三区在线观看 | 同性色老头性xxxx老头 | 国产欧美日本 | 亚洲精品国产精品乱码不卡√香蕉 | 欧美资源在线 | 麻豆av影院 | 日韩精品极品视频在线观看免费 | 欧美日一本 | 日韩激情一区二区 | 好吊日在线 | av 日韩 人妻 黑人 综合 无码 | 国模无码视频一区二区三区 | 国产高清免费在线 | 国产亚洲天堂 | 国产在线观看你懂的 | 国精产品一区一区三区免费视频 | 1024金沙人妻一区二区三区 | 日本一级黄 | 91大神在线免费观看 | 能看的毛片 | 96久久久 | 国产精品宾馆在线 | 色哟哟av | av不卡一区二区 | 日本九九热 | 欧美成人vr18sexvr | 亚洲午夜精品久久久久久app | 伊人黄色片 | 少妇被按摩师摸高潮了 | 欧美性大战久久久久久 | 不卡二区 | 色之久久综合 | 久久精品一区二区三 | 国内精品在线播放 | 免费在线性爱视频 |