【Boost】boost库中thread多线程详解1——thread入门与简介
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異常。
看下面一個小例子:
#include "stdafx.h" #include <iostream> #include <boost/thread.hpp> using namespace std;#define PRINT_DEBUG(x) cout<< x <<endl;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(&threadfun1); // 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()); } int _tmain(int argc, _TCHAR* argv[]) {test_thread_wait4();return 0; }
一、創建一個線程
創建線程
??? 當一個thread執行完成時,這個子線程就會消失。注意這個線程對象不會消失,它仍然是一個還處在它的生存期的C++對象。同理,當對一個堆上的線程對象的指針調用delete時候,線程對象被銷毀,操作系統的線程并不能保證就消失。
放棄時間片
??? boost::thread::yield(); (暫時沒有看出來它的實際作用)
??? 當前線程放棄余下的時間片。
等待一個線程
??? myThread.join();(類似windows API?WaitForSingleObject)
??? 調用這個方法的線程進入wait狀態,直到myThread代表的線程完成為止。如果它不結束的話,join方法就不會返回。join是一個等待子線程結束的最好的方法。如果主程序不調用join方法而直接結束,它的子線程有可能沒有執行完成,但是所有的子線程也隨之退出。不調用join方法,主線程就不會等待它的子線程。
#include <iostream> #include <boost/thread/thread.hpp> #include <boost/thread/xtime.hpp>struct MyThreadFunc {void operator( )( ) {// Do something long-running...} } threadFun;int main( ) {boost::thread myThread(threadFun);// Create a thread that starts// running threadFunboost::thread::yield( ); // Give up the main thread's timeslice// so the child thread can get some work// done.// Go do some other work...myThread.join( ); // The current (i.e., main) thread will wait// for myThread to finish before it returns}
l?boost::thread?
????boost::thread?是Boost庫對thread的封裝,隱藏了特定于操作系統的實現,提供給用戶統一的接口,實現了跨平臺,同時使用戶從繁雜的thread的特定于操作系統的API中解脫出來,取而代之的是更易理解、更優美的對象。每個thread對象代表一個線程。
一.?使用boost::thread創建線程
由于每一個boost::thread對應一個線程,所以創建線程就是創建一個boost::thread對象。
template<typename?Callable>
thread(Callable?func);
這里需要一個函數對象(函數指針、仿函數)
A?仿函數(測試失敗,不知道怎們回事回調不成功)
struct callable {void operator()(void){std::cout << "In callable ..." << std::endl;} }; boost::thread thread_call(struct callable);callable c; boost::thread thread_call(c); ?//這樣就可以了
B.全局函數.?
void func() {std::cout << "In fun..." << std::endl; } boost::thread thread_func(func);
C.?類成員函數
借助boost::bind?輕松實現
class thread_test {public:void invoke(){std::cout << "In thread_test::invoke..." << std::endl;} }; thread_test athread_test; boost::thread thread_member_call(boost::bind(&thread_test::invoke,&athread_test));
D.?含參函數對象
void func_arg(int num) {std::cout << "In func_arg ..." << " num=" << num << std::endl; } boost::thread thread_arg_bind(boost::bind(&func_arg,1012)); boost::thread thread_arg(func_arg,2012);
Boost::thread?中重載的構造
template?<class?F,class?A1,class?A2,...>
thread(F?f,A1?a1,A2?a2,...);
其實他內部也是通過boost::bind創建函數對象。
thread(boost::bind(f,a1,a2,...))
六、給線程函數傳遞一個參數
#include <iostream> #include <string> #include <functional> #include <boost/thread/thread.hpp>// A typedef to make the declarations below easier to read typedef void (*WorkerFunPtr)(const std::string&);template<typename FunT, // The type of the function being calledtypename ParamT>// The type of its parameter struct Adapter {Adapter(FunT f, ParamT& p) : // Construct this adapter and set thef_(f), p_(&p) {} // members to the function and its argvoid operator( )( ) { // This just calls the function with its argf_(*p_); } private:FunT f_;ParamT* p_; // Use the parameter's address to avoid extra copying };void worker(const std::string& s) {std::cout << s << '\n'; }int main( ) {std::string s1 = "This is the first thread!";std::string s2 = "This is the second thread!";boost::thread thr1(Adapter<WorkerFunPtr, std::string>(worker, s1));boost::thread thr2(Adapter<WorkerFunPtr, std::string>(worker, s2));thr1.join( );thr2.join( ); }
使用這個函數適配器類模板,你就可以給線程函數傳遞參數了。如果你需要傳遞多個參數,僅需要在這個適配器中增加另一個類型和成員變量。
BOOST庫的未來:
Boost線程庫正在計劃加入一些新特性。其中包括boost::read_write_mutex,它可以讓多個線程同時從共享區中讀取數據,但是一次只可能有一個線程向共享區寫入數據;boost::thread_barrier,它使得一組線程處于等待狀態,知道所有得線程都都進入了屏障區;boost::thread_pool,他允許執行一些小的routine而不必每一都要創建或是銷毀一個線程。Boost線程庫已經作為標準中的類庫技術報告中的附件提交給C++標準委員會,它的出現也為下一版C++標準吹響了第一聲號角。委員會成員對Boost線程庫的初稿給予了很高的評價,當然他們還會考慮其他的多線程庫。他們對在C++標準中加入對多線程的支持非常感興趣。從這一點上也可以看出,多線程在C++中的前途一片光明。
總結
以上是生活随笔為你收集整理的【Boost】boost库中thread多线程详解1——thread入门与简介的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C++中placement new操作符
- 下一篇: 【Boost】boost库中thread