Boost之多執行緒

2021-06-28 09:07:24 字數 4663 閱讀 6569

c++標準庫沒有涉及執行緒,在c++中,雖然不可能寫出標準相容的多執行緒程式,程式設計師可以使用特定作業系統提供的執行緒庫來寫出多執行緒程式來。可是,這至 少導致兩個突出的問題:作業系統普遍提供的是c庫,在c++中使用要更小心,每個作業系統都有自己的一套支援多執行緒的庫;另外,**不標準,不可移植。 boost.threads 可以解決這些問題。by firebird32

建立執行緒

boost::thread 類描述執行緒的執行。預設構造器建立乙個當前執行緒的執行的例項。過載構造器呼叫乙個無參也無返回值的函式物件,這個構造器啟動乙個新執行緒,其呼叫函式物件執行執行緒。

剛 開始好像這樣設計不如典型的c實現方式,建立乙個執行緒,乙個引數是void指標型別,可傳遞乙個被新執行緒呼叫的函式,另乙個引數可傳遞特定的資料到執行緒。 但是,boost.threads 用函式物件代替函式指標,這使得函式物件攜帶執行緒需要的資料。這種方法更靈活,並且是執行緒安全的。對於和函式物件庫的組合,比如 boost.bind ,這種設計允許你容易地傳遞任何數量的資料到新建立的執行緒中。

boost::thread 的 == 和 != 方法用來比較兩個執行緒物件是否在乙個執行緒中;可以呼叫join()方法等待執行緒結束。例1是乙個使用boost::thread 類的簡單例子,建立乙個新執行緒,在新執行緒中列印"hello world, i'm a thread!",在main執行緒中等待這個執行緒的結束。

例1:#include

#include

void hello()

int main(int argc, char* argv)

互斥體

我 們要知道在多執行緒程式中多個執行緒同時訪問共享資源時如何同步。假如乙個執行緒試圖修改共享資料的值,同時另乙個執行緒試圖讀這個值,結果是不確定的。為防止這 種情況發生,要用專門的原子型別和原子操作。有一種叫做互斥(mutex)。互斥在同一時刻僅允許乙個執行緒訪問共享資源。當乙個執行緒要訪問共享資源的時 候,它首先要「鎖定(lock)」互斥,假如另乙個執行緒先一步鎖定了互斥,這個執行緒要等待直到另乙個執行緒「解除鎖定(unlock)」互斥,這就保證了同 時僅有乙個執行緒訪問共享資源。

互斥有幾個變種。 boost.threads 支援兩類互斥,簡單互斥和遞迴互斥。簡單互斥僅能被鎖定一次,假如同一執行緒試圖鎖定互斥兩次,將造成死鎖,導致這個執行緒永遠等待下去。對於遞迴互斥,單個 執行緒可以鎖定互斥多次,也必須解除鎖定相同的次數,這樣才能使其他執行緒鎖定互斥。

對於這兩種互斥中,乙個執行緒可以通過如下三種途徑鎖定互斥:

1.嘗試且鎖定互斥,等待直到沒有其他執行緒鎖定互斥。

2.嘗試且鎖定互斥,假如其他執行緒已經鎖定互斥就立即返回。

3.嘗試且鎖定互斥,等待直到沒有其他執行緒鎖定互斥或直到指定的超時時間到。

boost.threads 提供以下六種互斥型別:boost::mutex, boost::try_mutex, boost::timed_mutex, boost::recursive_mutex, boost::recursive_try_mutex, 和 boost::recursive_timed_mutex。

假如乙個互斥被鎖定,但是沒有被解鎖,就會導致死鎖。這個錯誤非常普遍,因 此boost.threads的設計可以避免這種情況的發生。不直接使用鎖定、解鎖操作是可行的,使用鎖物件,鎖物件的構造中鎖定,在析構的時候解鎖。 c++語言的規則確保析構總是被呼叫,因此當異常發生時,互斥將被解鎖。

雖然這種機制對使用互斥有幫助,但是當異常發生時只能保證互斥被解鎖,卻可能使共享資料處於無效狀態。因此當異常發生時,使資料處於不一致狀態使程式設計師的責任。另外,共享的資源要在幾個執行緒之間共享,確保這些執行緒都能訪問到它。

例2是使用boost::mutex類的簡單例子。建立兩個執行緒,迴圈10次,寫id到std::cout。main執行緒等待這兩個執行緒結束。std::cout物件是共享資源,因此每個執行緒使用全域性互斥來保證每次只有乙個執行緒寫它。

例2:#include

#include

#include

boost::mutex io_mutex;

struct count

void operator()()

} int id; };

int main(int argc, char* argv)

例3:

// 這個例子和例2一樣,除了使用boost.bind來簡化建立執行緒攜帶資料,避免使用函式物件

#include

#include

#include

#include

boost::mutex io_mutex;

void count(int id)

} int main(int argc, char* argv)

條件變數

有時候鎖定共享資源且使用它滿足不了應用。有時共享資源在能夠使用前需要滿足一些特定狀態。例如,某執行緒試圖把資料從棧中取出,要是資料沒有到達它需要等待。互斥不能滿足這種同步。另一種同步型別,叫做條件變數,能夠滿足這種情況。

條 件變數總是和互斥、共享資源一起使用。乙個執行緒首先鎖定互斥,然後堅持共享資源是否處於特定狀態,假如不在所需要的狀態,執行緒在條件變數上等待。在等待期 間這個操作引發互斥解鎖,因此另一線程可以改變共享資源的狀態。當等待操作結束會確保互斥又被鎖定。當另一線程改變了共享資源的狀態,其需要通知等待條件 變數的執行緒,確使等待執行緒從等待操作返回。

例4是使用boost::condition類的簡單例子。

#include

#include

#include

#include

const int buf_size = 10;

const int iters = 100;

boost::mutex io_mutex;

class buffer

void put(int m)

while (full == buf_size)

cond.wait(lock); }

buf[p] = m;

p = (p+1) % buf_size;

++full;

cond.notify_one(); }

int get()

while (full == 0)

cond.wait(lk); }

int i = buf[c];

c = (c+1) % buf_size;

--full;

cond.notify_one();

return i; }

private:

boost::mutex mutex;

boost::condition cond;

unsigned int p, c, full;

int buf[buf_size]; };

buffer buf;

void writer()

buf.put(n); }

}void reader()

} }

int main(int argc, char* argv)

執行緒區域性儲存

許多函式被實現成不可重入。這意味著它是非執行緒安全的。就是說不能被多個執行緒同時呼叫。乙個不可重入的函式通常儲存靜態資料,或返回值指向靜態資料。例如,std::strtok是不可重入的,以為它用靜態資料儲存字串來分解成標記。

有 兩種途徑可使乙個不可重入函式變成可重入函式。一種途徑使修改函式介面,譬如可以傳遞乙個指向資料的指標或引用來代替靜態資料。這種方案簡單且效能最佳, 但是需要改變公共介面,導致應用**的大量修改。另一種途徑是不改變公共介面,用執行緒區域性儲存(有時也叫執行緒特定儲存)代替靜態資料。

線 程區域性儲存時資料和特定執行緒相關聯。多執行緒庫給出訪問執行緒區域性儲存的介面,可訪問當前執行緒的資料例項。每個執行緒提供其自己的資料例項,因此對同時訪問就不 會有任何問題。但是,執行緒區域性儲存比靜態資料或區域性資料要慢。因此這也不總是最好的方案。但是它是不改變公共介面的唯一方案。

例5是使用 boost::thread_specific_ptr 的簡單例子。

例5:#include

#include

#include

#include

boost::mutex io_mutex;

boost::thread_specific_ptrptr;

struct count

void operator()()

} int id; };

int main(int argc, char* argv)

僅執行一次的例程

一 般初始化例程僅執行一次,不能被多次執行,這就需要保證初始化例程是執行緒安全的,也就是說僅有乙個執行緒能呼叫執行。這種情況叫做「僅執行一次的例程」。一 個「僅執行一次的例程」在應用程式中只能被呼叫一次。假如多個執行緒試圖在同時執行這個例程,僅有乙個實際能執行,其他都將等待這個執行緒執行完畢後才返回。 boost.threads 通過boost::call_once 函式和boost::once_flag 標誌型別和乙個特定的巨集定義boost_once_init來支援「僅執行一次的例程」。

例6 展示了 boost::call_once 的簡單使用。

例6:#include

#include

#include

int i = 0;

boost::once_flag flag =

boost_once_init;

void init()

void thread()

int main(int argc, char* argv)

(十)boost庫之多執行緒

使用boost庫可以方便的建立乙個執行緒,並提供最多支援9個引數的執行緒函式,相對於void 來說,方便了很多,建立執行緒主要提供了一下3種方式 執行緒庫標頭檔案 include a 使用全域性函式作為執行緒執行體 voidfunc intncount int tmain int argc,tcha...

boost多執行緒

linux下編譯多執行緒程式 g o 1.out 1.cpp i boost include l boost lib lboost thread 建立執行緒 標頭檔案 namespace boost thread 構造乙個表示當前執行執行緒的執行緒物件 explicit thread const b...

boost 多執行緒使用

boost有幾種執行緒建立方式,現總結如下 首先看看boost thread的建構函式吧,boost thread有兩個建構函式 1 thread 構造乙個表示當前執行執行緒的執行緒物件 2 explicit thread const boost function0 threadfunc boost...