Boost Thread学习笔记

Boost Thread学习笔记

thread自然是boost ::thread库的主 角,但thread类的实现总体上是比较简单的,前面已经说过,thread只是一个跨平台的线程封装库,其中按照所使用的编译选项的不同,分别决定使用 Windows线程API还是pthread,或者Macintosh Carbon平台的thread实现。以下只讨论Windows,即使用 BOOST_HAS_WINTHREADS的情况。
thread类提供了两种构造函数:
thread ::thread ()
thread ::thread ( const function0 < void >& threadfunc )
第 一种构造函数用于调用GetCurrentThread构造一个当前线程的thread对象,第二种则通过传入一个函数或者一个functor来创建一个 新的线程。第二种情况下,thread类在其构造函数中间接调用CreateThread来创建线程,并将线程句柄保存到成员变量m_thread中,并 执行传入的函数,或执行functor的 operator  ()方法来启动工作线程。

我们可以用以下三种方式启动一个新线程:
1
、传递一个工作函数来构造一个工作线程

 1  #include  < boost / thread / thread.hpp >
 2  #include  < boost / thread / mutex.hpp >
 3  #include  < iostream >
 4 
 5  boost::mutex io_mutex;
 6 
 7  void  count()     //  worker function
 8  {
 9       for  ( int  i  =   0 ; i  <   10 ++ i)
10      {
11          boost::mutex::scoped_lock lock(io_mutex);
12          std::cout  <<  i  <<  std::endl;
13      }
14  }
15 
16  int  main( int  argc,  char *  argv[])
17  {
18      boost::thread thrd1( & count);
19      boost::thread thrd2( & count);
20      thrd1.join();
21      thrd2.join();
22 
23       return   0 ;
24  }
25 

2、传递一个functor对象来构造一个工作线程

 1  #include  < boost / thread / thread.hpp >
 2  #include  < boost / thread / mutex.hpp >
 3  #include  < iostream >
 4 
 5  boost::mutex io_mutex;
 6 
 7  struct count
 8  {
 9      count( int  id) : id(id) { }
10 
11       void  operator()()
12      {
13           for  ( int  i  =   0 ; i  <   10 ++ i)
14          {
15              boost::mutex::scoped_lock lock(io_mutex);         //  lock io, will be explained soon.
16              std::cout  <<  id  <<   " "   <<  i  <<  std::endl;
17          }
18      }
19 
20       int  id;
21  };
22 
23  int  main( int  argc,  char *  argv[])
24  {
25      boost::thread thrd1(count( 1 ));
26      boost::thread thrd2(count( 2 ));
27      thrd1.join();
28      thrd2.join();
29       return   0 ;
30  }
31 

3、无需将类设计成一个functor,借助bind来构造functor对象以创建工作线程

 1  #include  < boost / thread / thread.hpp >
 2  #include  < boost / thread / mutex.hpp >
 3  #include  < boost / bind.hpp >
 4  #include  < iostream >
 5 
 6  boost::mutex io_mutex;
 7 
 8  struct count
 9  {
10       static   int  num;
11       int  id;
12 
13      count() : id(num ++ ) {}
14 
15       int  do_count( int  n)
16      {
17           for  ( int  i  =   0 ; i  <  n;  ++ i)
18          {
19              boost::mutex::scoped_lock lock(io_mutex);
20              std::cout  <<  id  <<   " "   <<  i  <<  std::endl;
21          }
22           return  id;
23      }
24  };
25 
26  int  count::num  =   1 ;
27 
28  int  main( int  argc,  char *  argv[])
29  {
30      count c1;
31      boost::thread thrd1(boost::bind( & count::do_count,  & c1,  10 ));
32      thrd1.join();
33       return   0 ;
34  }

其中bind是一个函数模板,它可以根据后面的实例化参数构造出一个functor来,上面的boost ::bind (&count ::do_count , &c1 ,  10 )其实等价于返回了一个functor:
struct
 countFunctor
{

    int
 operator () ()
    {
        (&
c1 )->do_count ( 10 );     // just a hint, not actual code
    }
};

因此,以后就跟 2中是一样的了。




Boost Thread学习笔记二

除了thread,boost ::thread另一个重要组成部分是mutex,以及工作在mutex上的boost ::mutex ::scoped_lock、condition和barrier,这些都是为实现线程同步提供的。

mutex
boost提供的mutex有 6种:
boost ::mutex
boost ::try_mutex
boost ::timed_mutex
boost ::recursive_mutex
boost ::recursive_try_mutex
boost ::recursive_timed_mutex
下面仅对boost ::mutex进行分析。
mutex类是一个CriticalSection(临界区)封装类,它在构造函数中新建一个临界区并InitializeCriticalSection,然后用一个成员变量
void
* m_mutex ;
来保存该临界区结构。
除 此之外,mutex还提供了do_lock、do_unlock等方法,这些方法分别调用EnterCriticalSection、 LeaveCriticalSection来修改成员变量m_mutex(CRITICAL_SECTION结构指针)的状态,但这些方法都是 private的,以防止我们直接对mutex进行锁操作,所有的锁操作都必须通过mutex的友元类detail ::thread ::lock_ops <mutex >来完成,比较有意思的是,lock_ops的所有方法:lock、unlock、trylock等都是 static的,如lock_ops <Mutex >::lock的实现:
 1  template  < typename Mutex >
 2  class  lock_ops :  private  noncopyable
 3  {
 4 
 5  public :
 6       static   void  lock(Mutex &  m)
 7      {
 8          m.do_lock();
 9      }
10 
11  }
boost ::thread的设计者为什么会这么设计呢?我想大概是:
1
、boost ::thread的设计者不希望被我们直接操作mutex,改变其状态,所以mutex的所有方法都是 private的(除了构造函数,析构函数)。
2
、虽然我们可以通过lock_ops来修改mutex的状态,如:
 1  #include  < boost / thread / thread.hpp >
 2  #include  < boost / thread / mutex.hpp >
 3  #include  < boost / thread / detail / lock.hpp >
 4 
 5  int  main()
 6  {
 7      boost::mutex mt;
 8       // mt.do_lock();         //  Error! Can not access private member!
 9 
10      boost::detail::thread::lock_ops < boost::mutex > ::lock(mt);
11 
12       return   0 ;
13  }
但是,这是不推荐的,因为mutex、scoped_lock、condition、barrier是一套完整的类系,它们是相互协同工作的,像上面这么操作没有办法与后面的几个类协同工作。
scoped_lock
上面说过,不应该直接用lock_ops来操作mutex对象,那么,应该用什么呢?答案就是scoped_lock。与存在多种mutex一样,存在多种与mutex对应的scoped_lock:

scoped_lock
scoped_try_lock
scoped_timed_lock

这里我们只讨论scoped_lock。
scoped_lock是定义在 namespace boost ::detail ::thread下的,为了方便我们使用(也为了方便设计者),mutex使用了下面的 typedef
typedef
 detail ::thread ::scoped_lock <mutex > scoped_lock ;
这样我们就可以通过:
boost ::mutex ::scoped_lock
来使用scoped_lock类模板了。
由于scoped_lock的作用仅在于对mutex加锁 /解锁(即使mutex EnterCriticalSection /LeaveCriticalSection),因此,它的接口也很简单,除了构造函数外,仅有lock /unlock /locked(判断是否已加锁),及类型转换操作符 void *,一般我们不需要显式调用这些方法,因为scoped_lock的构造函数是这样定义的:

1  explicit scoped_lock(Mutex &  mx, bool initially_locked = true )
2      : m_mutex(mx), m_locked( false )
3  {
4       if  (initially_locked) lock();
5  }

注:m_mutex是一个mutex的引用。
因此,当我们不指定initially_locked参数构造一个scoped_lock对象 时,scoped_lock会自动对所绑定的mutex加锁,而析构函数会检查是否加锁,若已加锁,则解锁;当然,有些情况下,我们可能不需要构造时自动 加锁,这样就需要自己调用lock方法。后面的condition、barrier也会调用scoped_lock的lock、unlock方法来实现部 分方法。
正因为scoped_lock具有可在构造时加锁,析构时解锁的特性,我们经常会使用局部变量来实现对mutex的独占访问。

 1  #include  < boost / thread / thread.hpp >
 2  #include  < boost / thread / mutex.hpp >
 3  #include  < iostream >
 4 
 5  boost::mutex io_mutex;
 6 
 7  void  count()     //  worker function
 8  {
 9       for  ( int  i  =   0 ; i  <   10 ++ i)
10      {
11          boost::mutex::scoped_lock lock(io_mutex);
12          std::cout  <<  i  <<  std::endl;
13      }
14  }
15 
16  int  main( int  argc,  char *  argv[])
17  {
18      boost::thread thrd1( & count);
19      boost::thread thrd2( & count);
20      thrd1.join();
21      thrd2.join();
22 
23       return   0 ;
24  }

在每次输出信息时,为了防止整个输出过程被其它线程打乱,通过对io_mutex加锁(进入临界区),从而保证了输出的正确性。
在使用 scoped_lock时,我们有时候需要使用全局锁(定义一个全局mutex,当需要独占访问全局资源时,以该全局mutex为参数构造一个 scoped_lock对象即可。全局mutex可以是全局变量,也可以是类的静态方法等),有时候则需要使用对象锁(将mutex定义成类的成员变 量),应该根据需要进行合理选择。
Java的synchronized可用于对方法加锁,对代码段加锁,对对象加锁,对类加锁(仍然是对象级 的),这几种加锁方式都可以通过上面讲的对象锁来模拟;相反,在Java中实现全局锁好像有点麻烦,必须将请求封装到类中,以转换成上面的四种 synchronized形式之一。

condition
condition的接口如下:

 1  class  condition :  private  boost::noncopyable    //  Exposition only
 2  {
 3  public :
 4     //  construct/copy/destruct
 5    condition();
 6     ~ condition();
 7 
 8     //  notification
 9     void  notify_one();
10     void  notify_all();
11 
12     //  waiting
13    template < typename ScopedLock >   void  wait(ScopedLock & );
14    template < typename ScopedLock, typename Pred >   void  wait(ScopedLock & , Pred);
15    template < typename ScopedLock >
16      bool timed_wait(ScopedLock & const  boost::xtime & );
17    template < typename ScopedLock, typename Pred >
18      bool timed_wait(ScopedLock & , Pred);
19  };

其中wait用于等待某个condition的发生,而timed_wait则提供具有超时的wait功能,notify_one用于唤醒一个等待该condition发生的线程,notify_all则用于唤醒所有等待该condition发生的线程。

由于condition的语义相对较为复杂,它的实现也是整个boost ::thread库中最复杂的(对Windows版本而言,对支持pthread的版本而言,由于pthread已经提供了pthread_cond_t,使得condition实现起来也十分简单),下面对wait和notify_one进行简要分析。
condition内部包含了一个condition_impl对象,由该对象执行来处理实际的wait、notify_one ...等操作。






Boost Thread学习笔记三

下面先对condition_impl进行简要分析。
condition_impl在其构造函数中会创建两个Semaphore(信号量):m_gate、m_queue,及一个Mutex(互斥体,跟boost ::mutex类似,但boost ::mutex是基于CriticalSection <临界区 >的):m_mutex,其中:
m_queue
相当于当前所有等待线程的等待队列,构造函数中调用CreateSemaphore来创建Semaphore时,lMaximumCount参数被指定为 (std ::numeric_limits < long >::max )(),即便如此,condition的实现者为了防止出现大量等待线程的情况(以至于超过了 long的最大值),在线程因执行condition ::wait进入等待状态时会先:
WaitForSingleObject ( reinterpret_cast <HANDLE >(m_queue ), INFINITE );
以等待被唤醒,但很难想象什么样的应用需要处理这么多线程。
m_mutex
用于内部同步的控制。
但对于m_gate我很奇怪,我仔细研究了一下condition_imp的实现,还是不明白作者引入m_gate这个变量的用意何在,既然已经有了用于同步控制的m_mutex,再引入一个m_gate实在让我有点不解。

以下是condition ::wait调用的do_wait方法简化后的代码:

1  template  < typename M >
2  void  do_wait(M &  mutex)
3  {
4      m_impl.enter_wait();
5      lock_ops::unlock(mutex, state);     // 对传入的scoped_lock对象解锁,以便别的线程可以对其进行加锁,并执行某些处理,否则,本线程等待的condition永远不会发生(因为没有线程可以获得访问资源的权利以使condition发生)
6      m_impl.do_wait();     // 执行等待操作,等待其它线程执行notify_one或notify_all操作以获得
7      lock_ops::lock(mutex, state);     // 重新对scoped_lock对象加锁,获得独占访问资源的权利
8  }
condition ::timed_wait的实现方法与此类似,而notify_one、notify_all仅将调用请求转发给m_impl,就不多讲了。

虽然condition的内部实现比较复杂,但使用起来还是比较方便的。下面是一个使用condition的多Producer -多Consumer同步的例子:
  1  #include  < boost / thread / thread.hpp >
  2  #include  < boost / thread / mutex.hpp >
  3  #include  < boost / thread / condition.hpp >
  4  #include  < boost / thread / xtime.hpp >
  5 
  6  #include  < iostream >
  7  #include  < time.h >   //  for time()
  8 
  9  #include  < Windows.h >      //  for Sleep, change it for other platform, we can use
 10                           //  boost::thread::sleep, but it's too inconvenient.
 11 
 12  typedef boost::mutex::scoped_lock scoped_lock;
 13  boost::mutex io_mutex;
 14 
 15  class  Product
 16  {
 17       int  num;
 18  public :
 19      Product( int  num) : num(num) {}
 20 
 21      friend std::ostream &  operator <<  (std::ostream &  os, Product &  product)
 22      {
 23           return  os  <<  product.num;
 24      }
 25  };
 26 
 27  class  Mediator
 28  {
 29  private :
 30      boost::condition cond;
 31      boost::mutex mutex;
 32 
 33      Product **  pSlot;     //  product buffer/slot
 34      unsigned  int  slotCount,     //  buffer size
 35          productCount;  //  current product count
 36      bool stopFlag;     //  should all thread stop or not
 37 
 38  public :
 39      Mediator( const   int  slotCount) : slotCount(slotCount), stopFlag( false ), productCount( 0 )
 40      {
 41          pSlot  =   new  Product * [slotCount];
 42      }
 43 
 44      virtual  ~ Mediator()
 45      {
 46           for  ( int  i  =   0 ; i  <  static_cast < int > (productCount); i ++ )
 47          {
 48              delete pSlot[i];
 49          }
 50          delete [] pSlot;
 51      }
 52 
 53      bool Stop()  const  {  return  stopFlag; }
 54       void  Stop(bool) { stopFlag  =   true ; }
 55 
 56       void  NotifyAll()     //  notify all blocked thread to exit
 57      {
 58          cond.notify_all();
 59      }
 60 
 61      bool Put( Product *  pProduct)
 62      {
 63          scoped_lock lock(mutex);
 64           if  (productCount  ==  slotCount)
 65          {
 66              {
 67                  scoped_lock lock(io_mutex);
 68                  std::cout  <<   " Buffer is full. Waiting "   <<  std::endl;
 69              }
 70               while  ( ! stopFlag  &&  (productCount  ==  slotCount))
 71                  cond.wait(lock);
 72          }
 73           if  (stopFlag)  //  it may be notified by main thread to quit.
 74               return   false ;
 75 
 76          pSlot[ productCount ++  ]  =  pProduct;
 77          cond.notify_one();     //  this call may cause *pProduct to be changed if it wakes up a consumer
 78 
 79           return   true ;
 80      }
 81 
 82      bool Get(Product **  ppProduct)
 83      {
 84          scoped_lock lock(mutex);
 85           if  (productCount  ==   0 )
 86          {
 87              {
 88                  scoped_lock lock(io_mutex);
 89                  std::cout  <<   " Buffer is empty. Waiting "   <<  std::endl;
 90              }
 91               while  ( ! stopFlag  &&  (productCount  ==   0 ))
 92                  cond.wait(lock);
 93          }
 94           if  (stopFlag)  //  it may be notified by main thread to quit.
 95          {
 96               * ppProduct  =  NULL;
 97               return   false ;
 98          }
 99 
100           * ppProduct  =  pSlot[ -- productCount];
101          cond.notify_one();
102 
103           return   true ;
104      }
105  };
106 
107  class  Producer
108  {
109  private :
110      Mediator *  pMediator;
111       static  unsigned  int  num;
112      unsigned  int  id;     //  Producer id
113 
114  public :
115      Producer(Mediator *  pMediator) : pMediator(pMediator) { id  =  num ++ ; }
116 
117       void  operator() ()
118      {
119          Product *  pProduct;
120          srand( (unsigned)time( NULL )  +  id );     //  each thread need to srand differently
121           while  ( ! pMediator -> Stop())
122          {
123              pProduct  =   new  Product( rand()  %   100  );
124               //  must print product info before call Put, as Put may wake up a consumer
125               //  and cause *pProuct to be changed
126              {
127                  scoped_lock lock(io_mutex);
128                  std::cout  <<   " Producer[ "   <<  id  <<   " ] produces Product[ "
129                       <<   * pProduct  <<   " ] "   <<  std::endl;
130              }
131               if  ( ! pMediator -> Put(pProduct))     //  this function only fails when it is notified by main thread to exit
132                  delete pProduct;
133 
134              Sleep( 100 );
135          }
136      }
137  };
138 
139  unsigned  int  Producer::num  =   1 ;
140 
141  class  Consumer
142  {
143  private :
144      Mediator *  pMediator;
145       static  unsigned  int  num;
146      unsigned  int  id;     //  Consumer id
147 
148  public :
149      Consumer(Mediator *  pMediator) : pMediator(pMediator) { id  =  num ++ ; }
150 
151       void  operator() ()
152      {
153          Product *  pProduct  =  NULL;
154           while  ( ! pMediator -> Stop())
155          {
156               if  (pMediator -> Get( & pProduct))
157              {
158                  scoped_lock lock(io_mutex);
159                  std::cout  <<   " Consumer[ "   <<  id  <<   " ] is consuming Product[ "
160                       <<   * pProduct  <<   " ] "   <<  std::endl;
161                  delete pProduct;
162              }
163 
164              Sleep( 100 );
165          }
166      }
167  };
168 
169  unsigned  int  Consumer::num  =   1 ;
170 
171  int  main()
172  {
173      Mediator mediator( 2 );     //  we have only 2 slot to put products
174 
175       //  we have 2 producers
176      Producer producer1( & mediator);
177      boost::thread thrd1(producer1);
178      Producer producer2( & mediator);
179      boost::thread thrd2(producer2);
180       //  and we have 3 consumers
181      Consumer consumer1( & mediator);
182      boost::thread thrd3(consumer1);
183      Consumer consumer2( & mediator);
184      boost::thread thrd4(consumer2);
185      Consumer consumer3( & mediator);
186      boost::thread thrd5(consumer3);
187 
188       //  wait 1 second
189      Sleep( 1000 );
190       //  and then try to stop all threads
191      mediator.Stop( true );
192      mediator.NotifyAll();
193 
194       //  wait for all threads to exit
195      thrd1.join();
196      thrd2.join();
197      thrd3.join();
198      thrd4.join();
199      thrd5.join();
200 
201       return   0 ;
202  }







Boost Thread学习笔记四

barrier
barrier类的接口定义如下:
 1  class  barrier :  private  boost::noncopyable    //  Exposition only
 2  {
 3  public :
 4     //  construct/copy/destruct
 5    barrier(size_t n);
 6     ~ barrier();
 7 
 8     //  waiting
 9    bool wait();
10  };

barrier类为我们提供了这样一种控制线程同步的机制:
前n  -  1次调用wait函数将被阻塞,直到第n次调用wait函数,而此后第n  +  1次到第2n  -  1次调用wait也会被阻塞,直到第2n次调用,依次类推。
barrier ::wait的实现十分简单:

 1  barrier::barrier(unsigned  int  count)
 2      : m_threshold(count), m_count(count), m_generation( 0 )
 3  {
 4       if  (count  ==   0 )
 5           throw  std::invalid_argument( " count cannot be zero. " );
 6  }
 7 
 8  bool barrier::wait()
 9  {
10      boost::mutex::scoped_lock lock(m_mutex);     //  m_mutex is the base of barrier and is initilized by it's default constructor.
11      unsigned  int  gen  =  m_generation;     //  m_generation will be 0 for call 1~n-1, and 1 for n~2n - 1, and so on
12 
13       if  ( -- m_count  ==   0 )
14      {
15          m_generation ++ ;     //  cause m_generation to be changed in call n/2n/
16          m_count  =  m_threshold;     //  reset count
17          m_cond.notify_all();     //  wake up all thread waiting here
18           return   true ;
19      }
20 
21       while  (gen  ==  m_generation)     //  if m_generation is not changed, lock current thread.
22          m_cond.wait(lock);
23       return   false ;
24  }

因此,说白了也不过是mutex的一个简单应用。
以下是一个使用barrier的例子:

 1  #include  < boost / thread / thread.hpp >
 2  #include  < boost / thread / barrier.hpp >
 3 
 4  int  i  =   0 ;
 5  boost::barrier barr( 3 );     //  call barr.wait 3 * n times will release all threads in waiting
 6 
 7  void  thread()
 8  {
 9       ++ i;
10      barr.wait();
11  }
12 
13  int  main()
14  {
15      boost::thread thrd1( & thread);
16      boost::thread thrd2( & thread);
17      boost::thread thrd3( & thread);
18 
19      thrd1.join();
20      thrd2.join();
21      thrd3.join();
22 
23       return   0 ;
24  }

如果去掉其中thrd3相关的代码,将使得线程 12一直处于wait状态,进而使得主线程无法退出。

xtime
xtime是boost ::thread中用来表示时间的一个辅助类,它是一个仅包含两个成员变量的结构体:

1  struct xtime
2  {
3  //
4      xtime_sec_t sec;
5      xtime_nsec_t nsec;
6  };

condition ::timed_wait、thread ::sleep等涉及超时的函数需要用到xtime。
需要注意的是,xtime表示的不是一个时间间隔,而是一个时间点,因此使用起来很不方便。为了方便使用xtime,boost提供了一些辅助的xtime操作函数,如xtime_get、xtime_cmp等。
以下是一个使用xtime来执行sleep的例子(跟简单的一句Sleep比起来,实在是太复杂了),其中用到了xtime初始化函数xtime_get:
 1  #include  < boost / thread / thread.hpp >
 2  #include  < boost / thread / xtime.hpp >
 3  #include  < iostream >
 4 
 5  int  main()
 6  {
 7      boost::xtime xt;
 8      boost::xtime_get( & xt, boost::TIME_UTC);     //  initialize xt with current time
 9      xt.sec  +=   1 ;     //  change xt to next second
10      boost::thread::sleep(xt);     //  do sleep
11 
12      std::cout  <<   " 1 second sleep over. "   <<  std::endl;
13 
14       return   0 ;
15 










Boost Thread学习笔记五

多线程编程中还有一个重要的概念:Thread Local Store(TLS,线程局部存储),在boost中,TLS也被称作TSS,Thread Specific Storage。
boost ::thread库为我们提供了一个接口简单的TLS的面向对象的封装,以下是tss类的接口定义:
class  tss
{
public :
    tss(boost::function1
< void void *>*  pcleanup);
    
void *  get()  const ;
    
void  set( void *  value);
    
void  cleanup( void *  p);
};

分别用于获取、设置、清除线程局部存储变量,这些函数在内部封装了TlsAlloc、TlsGetValue、TlsSetValue等API操作,将它们封装成了OO的形式。
但boost将该类信息封装在detail名字空间内,即不推荐我们使用,当需要使用tss时,我们应该使用另一个使用更加方便的类:thread_specific_ptr,这是一个智能指针类,该类的接口如下:

 1  class  thread_specific_ptr :  private  boost::noncopyable    //  Exposition only
 2  {
 3  public :
 4     //  construct/copy/destruct
 5    thread_specific_ptr();
 6    thread_specific_ptr( void  ( * cleanup)( void * ));
 7     ~ thread_specific_ptr();
 8 
 9     //  modifier functions
10    T *  release();
11     void  reset(T *   =   0 );
12 
13     //  observer functions
14    T *  get()  const ;
15    T *  operator -> ()  const ;
16    T &  operator * ()()  const ;
17  };

即可支持get、reset、release等操作。
thread_specific_ptr类的实现十分简单,仅仅为了将tss类“改装”成智 能指针的样子,该类在其构造函数中会自动创建一个tss对象,而在其析构函数中会调用默认参数的reset函数,从而引起内部被封装的tss对象被析构, 达到“自动”管理内存分配释放的目的。

以下是一个运用thread_specific_ptr实现TSS的例子:
 1  #include  < boost / thread / thread.hpp >
 2  #include  < boost / thread / mutex.hpp >
 3  #include  < boost / thread / tss.hpp >
 4  #include  < iostream >
 5 
 6  boost::mutex io_mutex;
 7  boost::thread_specific_ptr < int >  ptr;     //  use this method to tell that this member will not shared by all threads
 8 
 9  struct count
10  {
11      count( int  id) : id(id) { }
12 
13       void  operator()()
14      {
15           if  (ptr.get()  ==   0 )     //  if ptr is not initialized, initialize it
16              ptr.reset( new   int ( 0 ));     //  Attention, we pass a pointer to reset (actually set ptr)
17 
18           for  ( int  i  =   0 ; i  <   10 ++ i)
19          {
20              ( * ptr) ++ ;
21              boost::mutex::scoped_lock lock(io_mutex);
22              std::cout  <<  id  <<   " "   <<   * ptr  <<  std::endl;
23          }
24      }
25 
26       int  id;
27  };
28 
29  int  main( int  argc,  char *  argv[])
30  {
31      boost::thread thrd1(count( 1 ));
32      boost::thread thrd2(count( 2 ));
33      thrd1.join();
34      thrd2.join();
35 
36       return   0 ;
37  }
此外,thread库还提供了一个很有趣的函数,call_once,在tss ::init的实现中就用到了该函数。
该函数的声明如下:
void
 call_once ( void  (*func )(), once_flag & flag );
该函数的Windows实现通过创建一个Mutex使所有的线程在尝试执行该函数时处于等待状态,直到有一个线程执行完了func函数,该函数的第二个参数表示函数func是否已被执行,该参数往往被初始化成BOOST_ONCE_INIT(即 0),如果你将该参数初始化成 1,则函数func将不被调用,此时call_once相当于什么也没干,这在有时候可能是需要的,比如,根据程序处理的结果决定是否需要call_once某函数func。
call_once在执行完函数func后,会将flag修改为 1,这样会导致以后执行call_once的线程(包括等待在Mutex处的线程和刚刚进入call_once的线程)都会跳过执行func的代码。

需要注意的是,该函数不是一个模板函数,而是一个普通函数,它的第一个参数 1是一个函数指针,其类型为 void  (*)(),而不是跟boost库的很多其它地方一样用的是function模板,不过这样也没有关系,有了boost ::bind这个超级武器,想怎么绑定参数就随你的便了,根据boost的文档,要求传入的函数不能抛出异常,但从实现代码中好像不是这样。

以下是一个典型的运用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则在两个线程中均执行了 ++操作。
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
As an AI language model, I cannot experience emotions, but I can provide information on how to boost threads in programming. Boost.Thread is a C++ library that provides a wide range of synchronization primitives, thread-safe containers, and other useful tools for multithreaded programming. Here are some tips for boosting threads in Boost.Thread: 1. Use mutexes: Mutexes are fundamental synchronization primitives that allow threads to safely access shared resources. Boost.Thread provides a variety of mutex types, including recursive and timed mutexes, that can be used to protect critical sections of code. 2. Use condition variables: Condition variables are a powerful tool for synchronizing threads. They allow threads to wait for a specific condition to be met before proceeding. Boost.Thread provides several types of condition variables, including timed condition variables, that can be used to implement complex synchronization patterns. 3. Use atomics: Atomic types provide a way to perform atomic operations on shared variables without the need for locks. Boost.Thread provides a variety of atomic types, including integers, booleans, and pointers, that can be used to implement lock-free algorithms. 4. Use thread-safe containers: Boost.Thread provides several thread-safe container types, including queues, stacks, and maps, that can be used to safely share data between threads. 5. Use thread pools: Thread pools provide a way to manage a pool of worker threads that can be used to execute tasks in parallel. Boost.Thread provides a thread pool implementation that can be used to boost performance in multithreaded applications. By using these tools and techniques, you can safely and efficiently boost threads in your C++ applications using Boost.Thread.

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值