1. 概述
線程就是,在同一程式同一時間內允許執行不同函數的離散處理隊列。 這使得一個長時間去進行某種特殊運算的函數在執行時不阻礙其他的函數變得十分重要。 線程實際上允許同時執行兩種函數,而這兩個函數不必相互等待。
一旦一個應用程式啟動,它僅包含一個預設線程。 此線程執行main() 函數。 在main()中被調用的函數則按這個線程的上下文順序地執行。 這樣的程式稱為單線程程式。
反之,那些建立新的線程的程式就是多線程程式。 他們不僅可以在同一時間執行多個函數,而且這在如今多核盛行的時代顯得尤為重要。 既然多核允許同時執行多個函數,這就使得對開發人員相應地使用這種處理能力提出了要求。 然而線程一直被用來當並發地執行多個函數,開發人員現在不得不仔細地構建應用來支援這種並發。 多線程編程知識也因此在多核系統時代變得越來越重要。
2. 線程管理2.1 情景1(test_thread_wait1)
在這個庫最重要的一個類就是boost::thread,它是在boost/thread.hpp裡定義的,用來建立一個新線程。下面的樣本來說明如何運用它。
建立線程裡執行的那個函數的名稱被傳遞到boost::thread的建構函式。 一旦上述樣本中的變數t 被建立,該 thread() 函數就在其所線上程中被立即執行。 同時在test_thread_wait1()裡也並發地執行該 threadfun1() 。
為了防止程式終止,就需要對建立線程調用join() 方法。join() 方法是一個阻塞調用:它可以暫停當前線程,直到調用 join() 的線程運行結束。這就使得test_thread_wait1()函數一直會等待到 threadfun1()運行結束。
正如在上面的例子中看到,一個特定的線程可以通過諸如t的變數訪問,通過這個變數等待著它的使用 join() 方法終止。 但是,即使 t 越界或者析構了,該線程也將繼續執行。 一個線程總是在一開始就綁定到一個類型為 boost::thread 的變數,但是一旦建立,就不在取決於它。 甚至還存在著一個叫detach()的方法,允許類型為boost::thread 的變數從它對應的線程裡分離。 當然了,像join()的方法之後也就不能被調用,因為這個變數不再是一個有效線程。
任何一個函數內可以做的事情也可以在一個線程內完成。 歸根結底,一個線程只不過是一個函數,除了它是同時執行的。 在上述例子中,使用一個迴圈把5個數字寫入標準輸出資料流。 為了減緩輸出,每一個迴圈中調用wait() 函數讓執行延遲了一秒。 wait() 可以調用一個名為sleep() 的函數,這個函數也來自於 Boost.Thread,位於 boost::this_thread 名空間內。
sleep() 要麼在預計的一段時間或一個特定的時間點後時才讓線程繼續執行。 通過傳遞一個類型為boost::posix_time::seconds 的對象,在這個例子裡我們指定了一段時間。 boost::posix_time::seconds 來自於Boost.DateTime庫,它被 Boost.Thread 用來管理和處理時間的資料。
雖然前面的例子說明了如何等待一個不同的線程,但下面的例子示範了如何通過所謂的中斷點讓一個線程中斷。
2.2 情景2(test_thread_wait2())
在一個線程對象上調用 interrupt() 會中斷相應的線程。在這方面,中斷意味著一個類型為boost::thread_interrupted的異常,它會在這個線程中拋出。然後這隻有線上程達到中斷點時才會發生。
如果給定的線程不包含任何中斷點,簡單調用interrupt() 就不會起作用。每當一個線程中斷點,它就會檢查interrupt() 是否被調用過。只有被調用過了, boost::thread_interrupted 異常才會相應地拋出。
Boost.Thread定義了一系列的中斷點,例如sleep()函數。由於sleep()在這個例子裡被調用了五次,該線程就檢查了五次它是否應該被中斷。然而sleep()之間的調用,卻不能使線程中斷。
一旦該程式被執行,它只會列印三個數字到標準輸出資料流。這是由於在test_thread_wait2()裡3秒後調用 interrupt()方法。因此,相應的線程被中斷,並拋出一個boost::thread_interrupted 異常。 這個異常線上程內也被正確地捕獲,catch處理雖然是空的。由於thread() 函數在處理常式後返回,線程也被終止。這反過來也將終止整個程式,因為test_thread_wait2()等待該線程使用join()終止該線程。
Boost.Thread定義包括上述 sleep()函數十個中斷。有了這些中斷點,線程可以很容易及時中斷。然而,他們並不總是最佳的選擇,因為中斷點必須事前讀入以檢查boost::thread_interrupted異常。
3.樣本
void wait(int seconds){boost::this_thread::sleep(boost::posix_time::seconds(seconds));}void threadfun1(){for (int i = 0; i < 5; ++i){wait(1);PRINT_DEBUG(i);}}void threadfun2() {try{for (int i = 0; i < 5; ++i){wait(1);PRINT_DEBUG(i);}}catch (boost::thread_interrupted&){PRINT_DEBUG("thread_interrupted");}}void test_thread_wait1(){boost::thread t(&threadfun1);// join()方法是一個阻塞調用:它可以暫停當前線程,直到調用join()的線程運行結束。t.join();}void test_thread_wait2(){boost::thread t(&threadfun2);wait(3);t.interrupt();t.join();}void test_thread_wait3(){ boost::thread t(&threadfun2); // timed_join()方法同樣也是一個阻塞調用:它可以暫停當前線程, // 直到調用join()的線程運行結束或者逾時 t.timed_join(boost::posix_time::seconds(3));}void test_thread_wait4(){ boost::thread t(&threadfun2); wait(3); // 當thread 與線程執行體分離時,線程執行體將不受影響地繼續執行, // 直到運行結束,或者隨主線程一起結束。 t.detach(); // 此時join無作用 t.join(); // t不再標識任何線程 {Not-any-thread} assert(t.get_id() == boost::thread::id());}