【Boost】boost库中thread多线程详解8——call_once仅运行一次
還有一個問題沒有解決:如何使得初始化工作(比如說構(gòu)造函數(shù))也是線程安全的。比方說,如果一個引用程序要產(chǎn)生唯一的全局的對象,由于實例化順序的問題,某個函數(shù)會被調(diào)用來返回一個靜態(tài)的對象,它必須保證第一次被調(diào)用時就產(chǎn)生這個靜態(tài)的對象。這里的問題就是如果多個線程同時調(diào)用了這個函數(shù),那么這個靜態(tài)對象的構(gòu)造函數(shù)就會被調(diào)用多次,這樣錯誤產(chǎn)生了。解決這個問題的方法就是所謂的“一次實現(xiàn)”(once routine)。“一次實現(xiàn)”在一個應(yīng)用程序只能執(zhí)行一次。如果多個線程想同時執(zhí)行這個操作,那么真正執(zhí)行的只有一個,而其他線程必須等這個操作結(jié)束。為了保證它只被執(zhí)行一次,這個routine由另一個函數(shù)間接的調(diào)用,而這個函數(shù)傳給它一個指針以及一個標(biāo)志著這個routine是否已經(jīng)被調(diào)用的特殊標(biāo)志。這個標(biāo)志是以靜態(tài)的方式初始化的,這也就保證了它在編譯期間就被初始化而不是運行時。因此也就沒有多個線程同時將它初始化的問題了。Boost線程庫提供了boost::call_once來支持“一次實現(xiàn)”,并且定義了一個標(biāo)志boost::once_flag及一個初始化這個標(biāo)志的宏BOOST_ONCE_INIT。List6是一個使用了boost::call_once的例子。其中定義了一個靜態(tài)的全局整數(shù),初始值為0;還有一個由BOOST_ONCE_INIT初始化的靜態(tài)boost::once_flag實例。main函數(shù)創(chuàng)建了兩個線程,它們都想通過傳入一個函數(shù)調(diào)用boost::call_once來初始化這個全局的整數(shù),這個函數(shù)是將它加1。main函數(shù)等待著兩個線程結(jié)束,并將最后的結(jié)果輸出的到std::cout。由最后的結(jié)果可以看出這個操作確實只被執(zhí)行了一次,因為它的值是1。
#include <boost/thread/thread.hpp> #include <boost/thread/once.hpp> #include <iostream>int i = 0; boost::once_flag flag = BOOST_ONCE_INIT;void init() {++i; }void thread() {boost::call_once(&init, flag); }int main(int argc, char* argv[]) {boost::thread thrd1(&thread);boost::thread thrd2(&thread);thrd1.join();thrd2.join();std::cout << i << std::endl;return 0; }#include <iostream> #include <boost/thread/thread.hpp> #include <boost/thread/once.hpp>// Some sort of connection class that should only be initialized once struct Conn {static void init( ) {++i_;}static boost::once_flag init_;static int i_;// ... };int Conn::i_ = 0; boost::once_flag Conn::init_ = BOOST_ONCE_INIT;void worker( ) {boost::call_once(Conn::init, Conn::init_);// Do the real work... }Conn c; // You probably don't want to use a global, so see the// next Recipeint main( ) {boost::thread_group grp;for (int i = 0; i < 100; ++i)grp.create_thread(worker);grp.join_all( );std::cout << c.i_ << '\n';// c.i_ = 1 }
一個共享資源不得不在某個地方被初始化,并且你希望第一次使用這個資源的線程來完成初始化工作。一個once_flag類型和call_once函數(shù)能夠保證多個線程不會重復(fù)的初始化同一個對象。首先,必須使用BOOST_ONCE_INIT宏來初始化這個once_flag對象。boost::once_flag Conn::init_ = BOOST_ONCE_INIT; 之后調(diào)用call_once函數(shù),boost::call_once(Conn::init, Conn::init_); 第一個形參是希望被執(zhí)行一次的初始化函數(shù)的地址。
總結(jié)
以上是生活随笔為你收集整理的【Boost】boost库中thread多线程详解8——call_once仅运行一次的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【Boost】boost库中thread
- 下一篇: 【Boost】boost库中thread