開始深入的TBB之旅之前,我們先看看怎麼初始化和終止TBB庫吧,畢竟這是使用TBB的一個基礎~~~
TBB裡提供了一個class:task_scheduler_init,該class會在constructor中初始化TBB,在destructor中終止TBB庫。
這樣我們就知道了最簡單的初始化&終止TBB的方法:
1 #include "tbb/task_scheduler_init.h" 2 using namespace tbb;3 4 int main() {5 task_scheduler_init init;6 ...7 return 0;8 }
這樣,由task_scheduler_init的constructor和destructor就提供了初始化和終止的功能。
下面我們來看看task_scheduler_init的constructor是怎樣的,開啟header file:tbb/task_scheduler_init.h,找到它的constructor的declaration:
1 //! Class representing reference to tbb scheduler. 2 /** A thread must construct a task_scheduler_init, and keep it alive, 3 during the time that it uses the services of class task. 4 @ingroup task_scheduling */ 5 class task_scheduler_init: internal::no_copy { 6 /** NULL if not currently initialized. */ 7 internal::scheduler* my_scheduler; 8 public: 9 //! Typedef for number of threads that is automatic. 10 static const int automatic = -1; 11 12 //! Argument to initialize() or constructor that causes initialization to be deferred. 13 static const int deferred = -2; 14 15 //! Ensure that scheduler exists for this thread 16 /** A value of -1 lets tbb decide on the number 17 of threads, which is typically the number of hardware threads. 18 For production code, the default value of -1 should be used, 19 particularly if the client code is mixed with third party clients 20 that might also use tbb. 21 22 The number_of_threads is ignored if any other task_scheduler_inits 23 currently exist. A thread may construct multiple task_scheduler_inits. 24 Doing so does no harm because the underlying scheduler is reference counted. */ 25 void initialize( int number_of_threads=automatic ); 26 27 //! Inverse of method initialize. 28 void terminate(); 29 30 //! Shorthand for default constructor followed by call to intialize(number_of_threads). 31 task_scheduler_init( int number_of_threads=automatic ) : my_scheduler(NULL) { 32 initialize( number_of_threads ); 33 } 34 35 //! Destroy scheduler for this thread if thread has no other live task_scheduler_inits. 36 ~task_scheduler_init() { 37 if( my_scheduler ) 38 terminate(); 39 internal::poison_pointer( my_scheduler ); 40 } 41 };
我們看到task_scheduler_init的constructor有一個預設參數number_of_threads,預設情況下取值為automatic(-1),它的含義是指在constructor時自動調用initialize函數,並建立出線程調度器。
number_of_threads可能的取值包括: automatic(-1):constructor時自動調用initialize()函數,建立合適的線程調度器 deferred(-2):表示在consturctor時不要調用initialize()函數初始化,而等到後面手動初始化 任意正整數:指定期望的線程數量,一般不要自己指定,除非你已經針對平台進行過特定的調節;當然我們也可以先使用deferred建立,然後在通過initialize(number_of_threads)來指定線程數量
我們來看一個典型的利用deferred參數來動態設定的例子:
1 int main( int argc, char* argv[] ) { 2 int nthread = strtol(argv[0],0,0); 3 task_scheduler_init init(task_scheduler_init::deferred); 4 if( nthread>=1 ) 5 init.initialize(nthread); 6 // ... code that uses task scheduler only if nthread>=1 ... 7 if( nthread>=1 ) 8 init.terminate(); 9 return 0;10 }
一個要注意的是:task_scheduler_init的構造是很費時的,不要每次使用TBB時都建立它,而是在main或者入口的地方建立一次就可以了。
在TBB深入部分我們會去看看task_scheduler_init是怎麼實現線程調度器的~~~(待續)