本帖最后由 yunh 于 2014-3-3 13:59 编辑
ACE 提供了一种特别的线程同步对象:ACE_Barrier,与其它的同步对象 Semaphore、Condition Variable、Mutex、Event、Readers/Writer Lock 不同,栅栏同步体在同步多个线程同时到达时更加有效,也更直观一些。下面是一个使用栅栏同步体的例子:- #include "stdafx.h"
- #include "ace/Barrier.h"
- #include "ace/Task_T.h"
- #include "ace/OS_NS_unistd.h"
- #define HAS_BARRIER
- class HA_CommandHandler : public ACE_Task <ACE_MT_SYNCH>
- {
- public:
- enum {
- N_THREADS = 5
- };
- HA_CommandHandler (ACE_Barrier &startup_barrier,
- ACE_Barrier &shutdown_barrier)
- : startup_barrier_ (startup_barrier)
- , shutdown_barrier_ (shutdown_barrier)
- {
- }
- void init_handler ()
- {
- ACE_OS::srand (ACE_Thread::self ());
- ACE_OS::sleep (ACE_Time_Value (0, ACE_OS::rand () % 1000000));
- }
- int handle_requests ()
- {
- for (int i=0; i<128; ++ i)
- {
- ACE_OS::sleep (ACE_Time_Value (0, ACE_OS::rand () % 100000));
- ACE_DEBUG ((LM_DEBUG, "(%t: %T) working %u\n", i));
- }
- return -1;
- }
- virtual int svc ()
- {
- init_handler ();
- #if defined (HAS_BARRIER)
- startup_barrier_.wait ();
- #endif
- ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t: %D) started\n")));
- while(handle_requests () > 0)
- ;
- #if defined (HAS_BARRIER)
- shutdown_barrier_.wait ();
- #endif
- ACE_DEBUG ((LM_DEBUG, ACE_TEXT ("(%t: %D) ended\n")));
- return 0;
- }
- private:
- ACE_Barrier &startup_barrier_;
- ACE_Barrier &shutdown_barrier_;
- };
- int ACE_TMAIN(int argc, ACE_TCHAR* argv[])
- {
- ACE_Barrier startup_barrier (HA_CommandHandler::N_THREADS);
- ACE_Barrier shutdown_barrier (HA_CommandHandler::N_THREADS);
- HA_CommandHandler handler (startup_barrier, shutdown_barrier);
- handler.activate (THR_NEW_LWP | THR_JOINABLE, HA_CommandHandler::N_THREADS);
- handler.wait ();
- return 0;
- }
复制代码 这个例子是直接从《ACE Programmer's Guide》P238 摘过来的,ACE_Barrier 的用法相对简单,在构造器中输入要同步的线程数,例子中是5,在需要同步的集合点,调用 wait 即可,如果没有达到预期的线程数 (5),wait 会陷入等待,当最后一个线程调用了 wait 后,会释放之前所有等待的线程,包括它自身,此时这些线程将如同开闸放水一般,同时向下继续奔涌。使用了同步体后的输出如下:- (1380: 11:32:20.434000) working 126
- (3240: 11:32:20.450000) working 127
- (1172: 11:32:20.450000) working 126
- (1380: 11:32:20.466000) working 127
- (1172: 11:32:20.481000) working 127
- (1172: Mon Mar 3 2014 11:32:20.481000) ended
- (3240: Mon Mar 3 2014 11:32:20.481000) ended
- (1380: Mon Mar 3 2014 11:32:20.481000) ended
- (6916: Mon Mar 3 2014 11:32:20.481000) ended
- (3780: Mon Mar 3 2014 11:32:20.481000) ended
复制代码 可以看到,在结束时各个线程的输出时间基本一样,为了与不使用同步体的情况做对比,我在例子代码中加入了预编译条件 HAS_BARRIER,将其注释并重编译后,就可以看到不一样的情况:- (7888: 11:34:19.946000) working 126
- (4992: 11:34:19.946000) working 121
- (2808: 11:34:19.962000) working 127
- (7888: 11:34:19.962000) working 127
- (4992: 11:34:19.962000) working 122
- (2808: Mon Mar 3 2014 11:34:19.962000) ended
- (7888: Mon Mar 3 2014 11:34:19.962000) ended
- (8092: 11:34:19.977000) working 122
- (4992: 11:34:19.993000) working 123
- (8092: 11:34:20.009000) working 123
- (4992: 11:34:20.024000) working 124
- (8092: 11:34:20.024000) working 124
- (8092: 11:34:20.024000) working 125
- (8092: 11:34:20.055000) working 126
- (4992: 11:34:20.055000) working 125
- (4992: 11:34:20.071000) working 126
- (8092: 11:34:20.087000) working 127
- (8092: Mon Mar 3 2014 11:34:20.087000) ended
- (4992: 11:34:20.102000) working 127
- (4992: Mon Mar 3 2014 11:34:20.102000) ended
复制代码 各个线程的结束时间就参差不齐了,看来 ACE_Barrier 确实起作用了。
总结一下,Semaphore 适合于解决生产者/消费者问题,用来控制活动线程的个数,保证与当前可用资源相匹配;Readers/Writer Lock 适合于一种资源被多个线程访问,其中读取者数量明显多于写入者;Mutex 为二元信号量,适合于锁定临界区代码;Event 与 Condition Variable 则比较适合于线程间的某种条件得到满足的通知;Barrier 则适合于在某一个集合点同步关联线程。
|