小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

Boost線程簡介(轉(zhuǎn)自Boost中文站) - 風(fēng)荷小筑 - 博客園

 xiaoqdu 2008-10-21

Boost線程簡介(轉(zhuǎn)自Boost中文站)

C++ Boost Thread 編程指南
  • 0 前言

  • 1 創(chuàng)建線程

  • 2 互斥體

  • 3 條件變量

  • 4 線程局部存儲

  • 5 僅運(yùn)行一次的例程

  • 6 Boost線程庫的未來

  • 7 參考資料:

  • 0 前言

  • 標(biāo)準(zhǔn)C++線程即將到來。CUJ預(yù)言它將衍生自Boost線程庫,現(xiàn)在就由Bill帶領(lǐng)我們探索一下Boost線程庫。

    就在幾年前,用多線程執(zhí)行程序還是一件非比尋常的事。然而今天互聯(lián)網(wǎng)應(yīng)用服務(wù)程序普遍使用多線程來提高與多客戶鏈接時的效率;為了達(dá)到最大的吞吐量,事務(wù) 服務(wù)器在單獨(dú)的線程上運(yùn)行服務(wù)程序;GUI應(yīng)用程序?qū)⒛切┵M(fèi)時,復(fù)雜的處理以線程的形式單獨(dú)運(yùn)行,以此來保證用戶界面能夠及時響應(yīng)用戶的操作。這樣使用多 線程的例子還有很多。

    但是C++標(biāo)準(zhǔn)并沒有涉及到多線程,這讓程序員們開始懷疑是否可能寫出多線程的C++程序。盡管不可能寫出符合標(biāo)準(zhǔn)的多線程程序,但是程序 員們還是會使用支持多線程的操作系統(tǒng)提供的多線程庫來寫出多線程C++程序。但是這樣做至少有兩個問題:這些庫大部分都是用C語言完成的,如果在C++程 序中要使用這些庫就必須十分小心;還有,每一個操作系統(tǒng)都有自己的一套支持多線程的類庫。因此,這樣寫出來得代碼是沒有標(biāo)準(zhǔn)可循的,也不是到處都適用的 (non-portable)。Boost線程庫就是為了解決所有這些問題而設(shè)計的。

    Boost是由C++標(biāo)準(zhǔn)委員會類庫工作組成員發(fā)起,致力于為C++開發(fā)新的類庫的組織?,F(xiàn)在它已經(jīng)有近2000名成員。許多庫都可以在Boost源碼的發(fā)布版本中找到。為了使這些類庫是線程安全的(thread-safe),Boost線程庫被創(chuàng)建了。

    許多C++專家都投身于Boost線程庫的開發(fā)中。所有接口的設(shè)計都是從0開始的,并不是C線程API的簡單封裝。許多C++特性(比如構(gòu)造函數(shù)和 析構(gòu)函數(shù),函數(shù)對象(function object)和模板)都被使用在其中以使接口更加靈活。現(xiàn)在的版本可以在POSIX,Win32和Macintosh Carbon平臺下工作。

  • 1 創(chuàng)建線程

  • 就像std::fstream類就代表一個文件一樣,boost::thread類就代表一個可執(zhí)行的線程。缺省構(gòu)造函數(shù)創(chuàng)建一個代表當(dāng)前執(zhí)行線程的實(shí) 例。一個重載的構(gòu)造函數(shù)以一個不需任何參數(shù)的函數(shù)對象作為參數(shù),并且沒有返回值。這個構(gòu)造函數(shù)創(chuàng)建一個新的可執(zhí)行線程,它調(diào)用了那個函數(shù)對象。

    起先,大家認(rèn)為傳統(tǒng)C創(chuàng)建線程的方法似乎比這樣的設(shè)計更有用,因?yàn)镃創(chuàng)建線程的時候會傳入一個void*指針,通過這種方法就可以傳入數(shù)據(jù)。然而,由于 Boost線程庫是使用函數(shù)對象來代替函數(shù)指針,那么函數(shù)對象本身就可以攜帶線程所需的數(shù)據(jù)。這種方法更具靈活性,也是類型安全(type-safe) 的。當(dāng)和Boost.Bind這樣的功能庫一起使用時,這樣的方法就可以讓你傳遞任意數(shù)量的數(shù)據(jù)給新建的線程。

    目前,由Boost線程庫創(chuàng)建的線程對象功能還不是很強(qiáng)大。事實(shí)上它只能做兩項(xiàng)操作。線程對象可以方便使用==和!=進(jìn)行比較來確定它們是否是代表同一個 線程;你還可以調(diào)用boost::thread::join來等待線程執(zhí)行完畢。其他一些線程庫可以讓你對線程做一些其他操作(比如設(shè)置優(yōu)先級,甚至是取 消線程)。然而,由于要在普遍適用(portable)的接口中加入這些操作不是簡單的事,目前仍在討論如何將這些操組加入到Boost線程庫中。

    Listing1展示了boost::thread類的一個最簡單的用法。 新建的線程只是簡單的在std::out上打印“hello,world”,main函數(shù)在它執(zhí)行完畢之后結(jié)束。


#include <boost/thread/thread.hpp>
#include <iostream>

void hello()
{
std::cout <<
"Hello world, I'm a thread!"
<< std::endl;
}

int main(int argc, char* argv[])
{
boost::thread thrd(&hello);
thrd.join();
return 0;
}

2 互斥體

任何寫過多線程程序的人都知道避免不同線程同時訪問共享區(qū)域的重要性。如果一個線程要改變共享區(qū)域中某個數(shù)據(jù),而與此同時另一線程正在讀這個數(shù)據(jù),那么結(jié) 果將是未定義的。為了避免這種情況的發(fā)生就要使用一些特殊的原始類型和操作。其中最基本的就是互斥體(mutex,mutual exclusion的縮寫)。一個互斥體一次只允許一個線程訪問共享區(qū)。當(dāng)一個線程想要訪問共享區(qū)時,首先要做的就是鎖?。╨ock)互斥體。如果其他的 線程已經(jīng)鎖住了互斥體,那么就必須先等那個線程將互斥體解鎖,這樣就保證了同一時刻只有一個線程能訪問共享區(qū)域。

互斥體的概念有不少變種。Boost線程庫支持兩大類互斥體,包括簡單互斥體(simple mutex)和遞歸互斥體(recursive mutex)。如果同一個線程對互斥體上了兩次鎖,就會發(fā)生死鎖(deadlock),也就是說所有的等待解鎖的線程將一直等下去。有了遞歸互斥體,單個 線程就可以對互斥體多次上鎖,當(dāng)然也必須解鎖同樣次數(shù)來保證其他線程可以對這個互斥體上鎖。

在這兩大類互斥體中,對于線程如何上鎖還有多個變種。一個線程可以有三種方法來對一個互斥體加鎖:

  1. 一直等到?jīng)]有其他線程對互斥體加鎖。

  2. 如果有其他互斥體已經(jīng)對互斥體加鎖就立即返回。

  3. 一直等到?jīng)]有其他線程互斥體加鎖,直到超時。

似乎最佳的互斥體類型是遞歸互斥體,它可以使用所有三種上鎖形式。然而每一個變種都是有代價的。所以Boost線程庫允許你根據(jù)不同的需要使用最有效率的互斥體類型。Boost線程庫提供了6中互斥體類型,下面是按照效率進(jìn)行排序:

boost::mutex,
boost::try_mutex, 
boost::timed_mutex, 
boost::recursive_mutex, 
boost::recursive_try_mutex,  
boost::recursive_timed_mutex

如果互斥體上鎖之后沒有解鎖就會發(fā)生死鎖。這是一個很普遍的錯誤,Boost線程庫就是要將其變成不可能(至少時很困難)。直接對互斥體上鎖和解鎖對于 Boost線程庫的用戶來說是不可能的。mutex類通過teypdef定義在RAII中實(shí)現(xiàn)的類型來實(shí)現(xiàn)互斥體的上鎖和解鎖。這也就是大家知道的 Scope Lock模式。為了構(gòu)造這些類型,要傳入一個互斥體的引用。構(gòu)造函數(shù)對互斥體加鎖,析構(gòu)函數(shù)對互斥體解鎖。C++保證了析構(gòu)函數(shù)一定會被調(diào)用,所以即使是 有異常拋出,互斥體也總是會被正確的解鎖。

這種方法保證正確的使用互斥體。然而,有一點(diǎn)必須注意:盡管Scope Lock模式可以保證互斥體被解鎖,但是它并沒有保證在異常拋出之后貢獻(xiàn)資源仍是可用的。所以就像執(zhí)行單線程程序一樣,必須保證異常不會導(dǎo)致程序狀態(tài)異 常。另外,這個已經(jīng)上鎖的對象不能傳遞給另一個線程,因?yàn)樗鼈兙S護(hù)的狀態(tài)并沒有禁止這樣做。

List2給出了一個使用boost::mutex的最簡單的例子。例子中共創(chuàng)建了兩個新的線程,每個線程都有10次循環(huán),在std::cout上打印出 線程id和當(dāng)前循環(huán)的次數(shù),而main函數(shù)等待這兩個線程執(zhí)行完才結(jié)束。std::cout就是共享資源,所以每一個線程都使用一個全局互斥體來保證同時 只有一個線程能向它寫入。

許多讀者可能已經(jīng)注意到List2中傳遞數(shù)據(jù)給線程還必須的手工寫一個函數(shù)。盡管這個例子很簡單,如果每一次都要寫這樣的代碼實(shí)在是讓人厭煩的事。別急, 有一種簡單的解決辦法。函數(shù)庫允許你通過將另一個函數(shù)綁定,并傳入調(diào)用時需要的數(shù)據(jù)來創(chuàng)建一個新的函數(shù)。 List3向你展示了如何使用Boost.Bind庫來簡化List2中的代碼,這樣就不必手工寫這些函數(shù)對象了。

例2:

#include <boost/thread/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <iostream>

boost::mutex io_mutex;

struct count
{
count(int id) : id(id) { }

void operator()()
{
for (int i = 0; i < 10; ++i)
{
boost::mutex::scoped_lock
lock(io_mutex);
std::cout << id << ": "
<< i << std::endl;
}
}

int id;
};

int main(int argc, char* argv[])
{
boost::thread thrd1(count(1));
boost::thread thrd2(count(2));
thrd1.join();
thrd2.join();
return 0;
}

例3: // 這個例子和例2一樣,除了使用Boost.Bind來簡化創(chuàng)建線程攜帶數(shù)據(jù),避免使用函數(shù)對象

#include <boost/thread/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/bind.hpp>
#include <iostream>

boost::mutex io_mutex;

void count(int id)
{
for (int i = 0; i < 10; ++i)
{
boost::mutex::scoped_lock
lock(io_mutex);
std::cout << id << ": " <<
i << std::endl;
}
}

int main(int argc, char* argv[])
{
boost::thread thrd1(
boost::bind(&count, 1));
boost::thread thrd2(
boost::bind(&count, 2));
thrd1.join();
thrd2.join();
return 0;
}

3 條件變量

有的時候僅僅依靠鎖住共享資源來使用它是不夠的。有時候共享資源只有某些狀態(tài)的時候才能夠使用。比方說,某個線程如果要從堆棧中讀取數(shù)據(jù),那么如果棧中沒 有數(shù)據(jù)就必須等待數(shù)據(jù)被壓棧。這種情況下的同步使用互斥體是不夠的。另一種同步的方式--條件變量,就可以使用在這種情況下。

條件變量的使用總是和互斥體及共享資源聯(lián)系在一起的。線程首先鎖住互斥體,然后檢驗(yàn)共享資源的狀態(tài)是否處于可使用的狀態(tài)。如果不是,那么線程就要等待條件 變量。要指向這樣的操作就必須在等待的時候?qū)⒒コ怏w解鎖,以便其他線程可以訪問共享資源并改變其狀態(tài)。它還得保證從等到得線程返回時互斥體是被上鎖得。當(dāng) 另一個線程改變了共享資源的狀態(tài)時,它就要通知正在等待條件變量得線程,并將之返回等待的線程。

List4是一個使用了boost::condition的簡單例子。有一個實(shí)現(xiàn)了有界緩存區(qū)的類和一個固定大小的先進(jìn)先出的容器。由于使用了互斥體 boost::mutex,這個緩存區(qū)是線程安全的。put和get使用條件變量來保證線程等待完成操作所必須的狀態(tài)。有兩個線程被創(chuàng)建,一個在 buffer中放入100個整數(shù),另一個將它們從buffer中取出。這個有界的緩存一次只能存放10個整數(shù),所以這兩個線程必須周期性的等待另一個線 程。為了驗(yàn)證這一點(diǎn),put和get在std::cout中輸出診斷語句。最后,當(dāng)兩個線程結(jié)束后,main函數(shù)也就執(zhí)行完畢了。

1 #include <boost/thread/thread.hpp>
2 #include <boost/thread/mutex.hpp>
3 #include <boost/thread/condition.hpp>
4 #include <iostream>

6 const int BUF_SIZE = 10;
7 const int ITERS = 100;

9 boost::mutex io_mutex;
10 
11 class buffer
12 {
13         public:
14         typedef boost::mutex::scoped_lock
15         scoped_lock;
16         
17         buffer()
18         : p(0), c(0), full(0)
19         {
20         }
21         
22         void put(int m)
23         {
24                 scoped_lock lock(mutex);
25                 if (full == BUF_SIZE)
26                 {
27                         {
28                                 boost::mutex::scoped_lock
29                                 lock(io_mutex);
30                                 std::cout <<
31                                 "Buffer is full. Waiting"
32                                 << std::endl;
33                         }
34                         while (full == BUF_SIZE)
35                         cond.wait(lock);
36                 }
37                 buf[p] = m;
38                 p = (p+1) % BUF_SIZE;
39                 ++full;
40                 cond.notify_one();
41         }
42         
43         int get()
44         {
45                 scoped_lock lk(mutex);
46                 if (full == 0)
47                 {
48                         {
49                                 boost::mutex::scoped_lock
50                                 lock(io_mutex);
51                                 std::cout <<
52                                 "Buffer is empty. Waiting"
53                                 << std::endl;
54                         }
55                         while (full == 0)
56                         cond.wait(lk);
57                 }
58                 int i = buf[c];
59                 c = (c+1) % BUF_SIZE;
60                 --full;
61                 cond.notify_one();
62                 return i;
63         }
64         
65         private:
66         boost::mutex mutex;
67         boost::condition cond;
68         unsigned int p, c, full;
69         int buf[BUF_SIZE];
70 };
71 
72 buffer buf;
73 
74 void writer()
75 {
76         for (int n = 0; n < ITERS; ++n)
77         {
78                 {
79                         boost::mutex::scoped_lock
80                         lock(io_mutex);
81                         std::cout << "sending: "
82                         << n << std::endl;
83                 }
84                 buf.put(n);
85         }
86 }
87 
88 void reader()
89 {
90         for (int x = 0; x < ITERS; ++x)
91         {
92                 int n = buf.get();
93                 {
94                         boost::mutex::scoped_lock
95                         lock(io_mutex);
96                         std::cout << "received: "
97                         << n << std::endl;
98                 }
99         }
100 }
101 
102 int main(int argc, char* argv[])
103 {
104         boost::thread thrd1(&reader);
105         boost::thread thrd2(&writer);
106         thrd1.join();
107         thrd2.join();
108         return 0;
109 }

4 線程局部存儲

大多數(shù)函數(shù)都不是可重入的。這也就是說在某一個線程已經(jīng)調(diào)用了一個函數(shù)時,如果你再調(diào)用同一個函數(shù),那么這樣是不安全的。一個不可重入的函數(shù)通過連續(xù)的調(diào) 用來保存靜態(tài)變量或者是返回一個指向靜態(tài)數(shù)據(jù)的指針。 舉例來說,std::strtok就是不可重入的,因?yàn)樗褂渺o態(tài)變量來保存要被分割成符號的字符串。

有兩種方法可以讓不可重用的函數(shù)變成可重用的函數(shù)。第一種方法就是改變接口,用指針或引用代替原先使用靜態(tài)數(shù)據(jù)的地方。比方說,POSIX定義了 strok_r,std::strtok中的一個可重入的變量,它用一個額外的char**參數(shù)來代替靜態(tài)數(shù)據(jù)。這種方法很簡單,而且提供了可能的最佳效 果。但是這樣必須改變公共接口,也就意味著必須改代碼。另一種方法不用改變公有接口,而是用本地存儲線程(thread local storage)來代替靜態(tài)數(shù)據(jù)(有時也被成為特殊線程存儲,thread-specific storage)。

Boost線程庫提供了智能指針boost::thread_specific_ptr來訪問本地存儲線程。每一個線程第一次使用這個智能指針的實(shí)例時, 它的初值是NULL,所以必須要先檢查這個它的只是否為空,并且為它賦值。Boost線程庫保證本地存儲線程中保存的數(shù)據(jù)會在線程結(jié)束后被清除。

List5是一個使用boost::thread_specific_ptr的簡單例子。其中創(chuàng)建了兩個線程來初始化本地存儲線程,并有10次循環(huán),每一 次都會增加智能指針指向的值,并將其輸出到std::cout上(由于std::cout是一個共享資源,所以通過互斥體進(jìn)行同步)。main線程等待這 兩個線程結(jié)束后就退出。從這個例子輸出可以明白的看出每個線程都處理屬于自己的數(shù)據(jù)實(shí)例,盡管它們都是使用同一個 boost::thread_specific_ptr。

例5:

1 #include <boost/thread/thread.hpp>
2 #include <boost/thread/mutex.hpp>
3 #include <boost/thread/tss.hpp>
4 #include <iostream>

6 boost::mutex io_mutex;
7 boost::thread_specific_ptr<int> ptr;

9 struct count
10 {
11         count(int id) : id(id) { }
12         
13         void operator()()
14         {
15                 if (ptr.get() == 0)
16                 ptr.reset(new int(0));
17                 
18                 for (int i = 0; i < 10; ++i)
19                 {
20                         (*ptr)++;
21                         boost::mutex::scoped_lock
22                         lock(io_mutex);
23                         std::cout << id << ": "
24                         << *ptr << std::endl;
25                 }
26         }
27         
28         int id;
29 };
30 
31 int main(int argc, char* argv[])
32 {
33         boost::thread thrd1(count(1));
34         boost::thread thrd2(count(2));
35         thrd1.join();
36         thrd2.join();
37         return 0;
38 }
posted @ 2008-08-02 22:15 風(fēng)荷小筑 閱讀(40) 評論(0)  編輯 收藏 網(wǎng)摘

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點(diǎn)擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多