yunh 发表于 2014-3-3 13:54:14

ACE 栅栏同步体介绍

本帖最后由 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 Mar3 2014 11:32:20.481000) ended
(3240: Mon Mar3 2014 11:32:20.481000) ended
(1380: Mon Mar3 2014 11:32:20.481000) ended
(6916: Mon Mar3 2014 11:32:20.481000) ended
(3780: Mon Mar3 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 Mar3 2014 11:34:19.962000) ended
(7888: Mon Mar3 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 Mar3 2014 11:34:20.087000) ended
(4992:11:34:20.102000) working 127
(4992: Mon Mar3 2014 11:34:20.102000) ended      各个线程的结束时间就参差不齐了,看来 ACE_Barrier 确实起作用了。
      总结一下,Semaphore 适合于解决生产者/消费者问题,用来控制活动线程的个数,保证与当前可用资源相匹配;Readers/Writer Lock 适合于一种资源被多个线程访问,其中读取者数量明显多于写入者;Mutex 为二元信号量,适合于锁定临界区代码;Event 与 Condition Variable 则比较适合于线程间的某种条件得到满足的通知;Barrier 则适合于在某一个集合点同步关联线程。

freeeyes 发表于 2014-3-3 14:28:12

好贴,加精
页: [1]
查看完整版本: ACE 栅栏同步体介绍