BOOST源码笔记(1) - boost::call_once

boost::call_once应用及其实现

 

以下是一个典型的运用call_once实现一次初始化的例子:

 1  #include  < boost / thread / thread.hpp >
 2  #include  < boost / thread / once.hpp >
 3  #include  < iostream >
 4 
 5  int  i  =   0 ;
 6  int  j  =   0 ;
 7  boost::once_flag flag  =  BOOST_ONCE_INIT;
 8 
 9  void  init()
10  {
11       ++ i;
12  }
13 
14  void  thread()
15  {
16      boost::call_once( & init, flag);
17       ++ j;
18  }
19 
20  int  main( int  argc,  char *  argv[])
21  {
22      boost::thread thrd1( & thread);
23      boost::thread thrd2( & thread);
24      thrd1.join();
25      thrd2.join();
26 
27      std::cout  <<  i  <<  std::endl;
28      std::cout  <<  j  <<  std::endl;
29 
30       return   0 ;
31  }

结果显示,全局变量i仅被执行了一次++操作,而变量j则在两个线程中均执行了++操作。

 

原理:

    利用传入的 flag的地址和current process id 为变量来构造一个字符串, 并用此字符串构造一个named mutex, 使得此mutex在同一进程内,相对同个flag唯一.第一次获得此mutex所有权的线程执行传入的函数对象, 并将flag修改为特定的值, 其他线程判断flag是否被修改到这个特定的值, 如果修改了则不调用函数直接跳过. 采用双判断机制来减少调用waitforsingleobject的次数,提高效率

关键原码:

 

void call_once(once_flag& flag,Function f)
    {
        // Try for a quick win: if the procedure has already been called
        // just skip through:
        long const function_complete_flag_value=0xc15730e2; //第一次完成call后将flag值修改为此值

        if(::boost::detail::interlocked_read_acquire(&flag)!=function_complete_flag_value)//第一次判断,可以减少waitforsingleobject次数
        {
            void* const mutex_handle(::boost::detail::create_once_mutex(&flag));//创建进程内唯一的metux
            BOOST_ASSERT(mutex_handle);
            detail::win32::handle_manager const closer(mutex_handle); //handle guard, 离开作用域自动closehandle
            detail::win32_mutex_scoped_lock const lock(mutex_handle); //mutex guard, 构造函数中waitforsingleobject(传入的mutex handle),离开作用域自动releaseMutex
       
            if(flag!=function_complete_flag_value)//第二次判断,waitforsingleobject后再次判断call是否已经调用
            {
                f();
                BOOST_INTERLOCKED_EXCHANGE(&flag,function_complete_flag_value);//原子操作,给flag赋值
            }
        }
    }

 

 

你可能感兴趣的:(BOOST源码笔记(1) - boost::call_once)