【Boost】boost库中thread多线程详解1——thread入门与简介
1. 概述
線程就是,在同一程序同一時間內(nèi)允許執(zhí)行不同函數(shù)的離散處理隊列。 這使得一個長時間去進行某種特殊運算的函數(shù)在執(zhí)行時不阻礙其他的函數(shù)變得十分重要。 線程實際上允許同時執(zhí)行兩種函數(shù),而這兩個函數(shù)不必相互等待。 一旦一個應(yīng)用程序啟動,它僅包含一個默認(rèn)線程。 此線程執(zhí)行main() 函數(shù)。 在main()中被調(diào)用的函數(shù)則按這個線程的上下文順序地執(zhí)行。 這樣的程序稱為單線程程序。 反之,那些創(chuàng)建新的線程的程序就是多線程程序。 他們不僅可以在同一時間執(zhí)行多個函數(shù),而且這在如今多核盛行的時代顯得尤為重要。 既然多核允許同時執(zhí)行多個函數(shù),這就使得對開發(fā)人員相應(yīng)地使用這種處理能力提出了要求。 然而線程一直被用來當(dāng)并發(fā)地執(zhí)行多個函數(shù),開發(fā)人員現(xiàn)在不得不仔細地構(gòu)建應(yīng)用來支持這種并發(fā)。 多線程編程知識也因此在多核系統(tǒng)時代變得越來越重要。2. 線程管理
2.1 情景1(test_thread_wait1)
在這個庫最重要的一個類就是boost::thread,它是在boost/thread.hpp里定義的,用來創(chuàng)建一個新線程。下面的示例來說明如何運用它。 新建線程里執(zhí)行的那個函數(shù)的名稱被傳遞到boost::thread的構(gòu)造函數(shù)。 一旦上述示例中的變量t 被創(chuàng)建,該 thread() 函數(shù)就在其所在線程中被立即執(zhí)行。 同時在test_thread_wait1()里也并發(fā)地執(zhí)行該 threadfun1() 。 為了防止程序終止,就需要對新建線程調(diào)用join() 方法。join() 方法是一個阻塞調(diào)用:它可以暫停當(dāng)前線程,直到調(diào)用 join() 的線程運行結(jié)束。這就使得test_thread_wait1()函數(shù)一直會等待到 threadfun1()運行結(jié)束。 正如在上面的例子中看到,一個特定的線程可以通過諸如t的變量訪問,通過這個變量等待著它的使用 join() 方法終止。 但是,即使 t 越界或者析構(gòu)了,該線程也將繼續(xù)執(zhí)行。 一個線程總是在一開始就綁定到一個類型為 boost::thread 的變量,但是一旦創(chuàng)建,就不在取決于它。 甚至還存在著一個叫detach()的方法,允許類型為boost::thread 的變量從它對應(yīng)的線程里分離。 當(dāng)然了,像join()的方法之后也就不能被調(diào)用,因為這個變量不再是一個有效的線程。 任何一個函數(shù)內(nèi)可以做的事情也可以在一個線程內(nèi)完成。 歸根結(jié)底,一個線程只不過是一個函數(shù),除了它是同時執(zhí)行的。 在上述例子中,使用一個循環(huán)把5個數(shù)字寫入標(biāo)準(zhǔn)輸出流。 為了減緩輸出,每一個循環(huán)中調(diào)用wait() 函數(shù)讓執(zhí)行延遲了一秒。 wait() 可以調(diào)用一個名為sleep() 的函數(shù),這個函數(shù)也來自于 Boost.Thread,位于 boost::this_thread 名空間內(nèi)。 sleep() 要么在預(yù)計的一段時間或一個特定的時間點后時才讓線程繼續(xù)執(zhí)行。 通過傳遞一個類型為boost::posix_time::seconds 的對象,在這個例子里我們指定了一段時間。 boost::posix_time::seconds 來自于Boost.DateTime庫,它被 Boost.Thread 用來管理和處理時間的數(shù)據(jù)。 雖然前面的例子說明了如何等待一個不同的線程,但下面的例子演示了如何通過所謂的中斷點讓一個線程中斷。2.2?情景2(test_thread_wait2())
在一個線程對象上調(diào)用 interrupt() 會中斷相應(yīng)的線程。在這方面,中斷意味著一個類型為boost::thread_interrupted的異常,它會在這個線程中拋出。然后這只有在線程達到中斷點時才會發(fā)生。如果給定的線程不包含任何中斷點,簡單調(diào)用interrupt() 就不會起作用。每當(dāng)一個線程中斷點,它就會檢查interrupt() 是否被調(diào)用過。只有被調(diào)用過了, boost::thread_interrupted 異常才會相應(yīng)地拋出。Boost.Thread定義了一系列的中斷點,例如sleep()函數(shù)。由于sleep()在這個例子里被調(diào)用了五次,該線程就檢查了五次它是否應(yīng)該被中斷。然而sleep()之間的調(diào)用,卻不能使線程中斷。一旦該程序被執(zhí)行,它只會打印三個數(shù)字到標(biāo)準(zhǔn)輸出流。這是由于在test_thread_wait2()里3秒后調(diào)用 interrupt()方法。因此,相應(yīng)的線程被中斷,并拋出一個boost::thread_interrupted 異常。 這個異常在線程內(nèi)也被正確地捕獲,catch處理雖然是空的。由于thread() 函數(shù)在處理程序后返回,線程也被終止。這反過來也將終止整個程序,因為test_thread_wait2()等待該線程使用join()終止該線程。Boost.Thread定義包括上述 sleep()函數(shù)十個中斷。有了這些中斷點,線程可以很容易及時中斷。然而,他們并不總是最佳的選擇,因為中斷點必須事前讀入以檢查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()方法是一個阻塞調(diào)用:它可以暫停當(dāng)前線程,直到調(diào)用join()的線程運行結(jié)束。 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()方法同樣也是一個阻塞調(diào)用:它可以暫停當(dāng)前線程, // 直到調(diào)用join()的線程運行結(jié)束或者超時 t.timed_join(boost::posix_time::seconds(3)); } void test_thread_wait4() { boost::thread t(&threadfun2); wait(3); //當(dāng)thread 與線程執(zhí)行體分離時,線程執(zhí)行體將不受影響地繼續(xù)執(zhí)行, //直到運行結(jié)束,或者隨主線程一起結(jié)束。 t.detach(); // 此時join無作用 t.join(); // t不再標(biāo)識任何線程 {Not-any-thread} assert(t.get_id() == boost::thread::id()); } int _tmain(int argc, _TCHAR* argv[]) {test_thread_wait4();return 0; }
一、創(chuàng)建一個線程
創(chuàng)建線程
??? 當(dāng)一個thread執(zhí)行完成時,這個子線程就會消失。注意這個線程對象不會消失,它仍然是一個還處在它的生存期的C++對象。同理,當(dāng)對一個堆上的線程對象的指針調(diào)用delete時候,線程對象被銷毀,操作系統(tǒng)的線程并不能保證就消失。
放棄時間片
??? boost::thread::yield(); (暫時沒有看出來它的實際作用)
??? 當(dāng)前線程放棄余下的時間片。
等待一個線程
??? myThread.join();(類似windows API?WaitForSingleObject)
??? 調(diào)用這個方法的線程進入wait狀態(tài),直到myThread代表的線程完成為止。如果它不結(jié)束的話,join方法就不會返回。join是一個等待子線程結(jié)束的最好的方法。如果主程序不調(diào)用join方法而直接結(jié)束,它的子線程有可能沒有執(zhí)行完成,但是所有的子線程也隨之退出。不調(diào)用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的封裝,隱藏了特定于操作系統(tǒng)的實現(xiàn),提供給用戶統(tǒng)一的接口,實現(xiàn)了跨平臺,同時使用戶從繁雜的thread的特定于操作系統(tǒng)的API中解脫出來,取而代之的是更易理解、更優(yōu)美的對象。每個thread對象代表一個線程。
一.?使用boost::thread創(chuàng)建線程
由于每一個boost::thread對應(yīng)一個線程,所以創(chuàng)建線程就是創(chuàng)建一個boost::thread對象。
template<typename?Callable>
thread(Callable?func);
這里需要一個函數(shù)對象(函數(shù)指針、仿函數(shù))
A?仿函數(shù)(測試失敗,不知道怎們回事回調(diào)不成功)
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.全局函數(shù).?
void func() {std::cout << "In fun..." << std::endl; } boost::thread thread_func(func);
C.?類成員函數(shù)
借助boost::bind?輕松實現(xiàn)
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.?含參函數(shù)對象
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?中重載的構(gòu)造
template?<class?F,class?A1,class?A2,...>
thread(F?f,A1?a1,A2?a2,...);
其實他內(nèi)部也是通過boost::bind創(chuàng)建函數(shù)對象。
thread(boost::bind(f,a1,a2,...))
六、給線程函數(shù)傳遞一個參數(shù)
#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( ); }
使用這個函數(shù)適配器類模板,你就可以給線程函數(shù)傳遞參數(shù)了。如果你需要傳遞多個參數(shù),僅需要在這個適配器中增加另一個類型和成員變量。
BOOST庫的未來:
Boost線程庫正在計劃加入一些新特性。其中包括boost::read_write_mutex,它可以讓多個線程同時從共享區(qū)中讀取數(shù)據(jù),但是一次只可能有一個線程向共享區(qū)寫入數(shù)據(jù);boost::thread_barrier,它使得一組線程處于等待狀態(tài),知道所有得線程都都進入了屏障區(qū);boost::thread_pool,他允許執(zhí)行一些小的routine而不必每一都要創(chuàng)建或是銷毀一個線程。Boost線程庫已經(jīng)作為標(biāo)準(zhǔn)中的類庫技術(shù)報告中的附件提交給C++標(biāo)準(zhǔn)委員會,它的出現(xiàn)也為下一版C++標(biāo)準(zhǔn)吹響了第一聲號角。委員會成員對Boost線程庫的初稿給予了很高的評價,當(dāng)然他們還會考慮其他的多線程庫。他們對在C++標(biāo)準(zhǔn)中加入對多線程的支持非常感興趣。從這一點上也可以看出,多線程在C++中的前途一片光明。
總結(jié)
以上是生活随笔為你收集整理的【Boost】boost库中thread多线程详解1——thread入门与简介的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: C++中placement new操作符
- 下一篇: 【Boost】boost库中thread