• ACE


    原文出自http://www.cnblogs.com/binchen-china,禁止转载。

    上篇提到用Reactor模式,利用I/O复用,获得Socket数据并且实现I/O层单线程并发,和dispatch层把不同的I/O绑定到了不同的Event中去处理。也就是已经实现了多个client连接和通信,且可以把不同的I/O与Event句柄绑定,指定处理函数。

    但是问题来了,多个用户连接时,I/O层可以通过复用以较快的速度处理连接和把过来的数据关联到绑定的Event函数执行。但是绑定Event函数获得数据后,需要逐个处理,当大量数据从I/O层过来,所有数据共享线程,而且业务代码又是非常耗时的。每个socket通道过来的数据都要以单线程的方式执行业务,效率就非常低了。必须当线程空闲时才能占有,所以这里有必要引入线程池去处理业务。

    image 

    ACE_Task类封装了线程和消息队列,使这些功能以面向对象的方式提供给用户,其中消息队列并非IPC中的消息队列,在ACE实现实际为普通队列。利用ACE_Task可以生产一个或一组线程,并且为线程池之间的消息交互提供了接口和队列。在Event部分,我们可以利用线程池来解决效率问题。

    下面提供线程池实现代码:

     1 #include "ace/Task.h"
     2 #include "ace/OS.h" 
     3 #include <string>
     4 
     5 using namespace std;
     6 
     7 string g_strMsg[] = {
     8 "MESSAGE 1",
     9 "MESSAGE 2",
    10 "MESSAGE 3",
    11 "MESSAGE 4",
    12 "MESSAGE 5",
    13 "MESSAGE 6",
    14 };
    15 
    16 class TaskThread: public ACE_Task<ACE_MT_SYNCH>
    17 {
    18 public:
    19     virtual int svc(void)
    20     {
    21         ACE_Message_Block *Msg;// = new ACE_Message_Block();
    22         while(1)
    23         {
    24             getq(Msg);            //空闲线程阻塞
    25             ACE_DEBUG((LM_INFO,"recevie msg:%s,time:%d
    ",Msg->rd_ptr(),(int)ACE_OS::time()));
    26             Msg->release();        //release
    27             ACE_OS::sleep(1);    //延时1s模拟业务处理耗时
    28         }
    29     }
    30 };
    31 
    32 class Message
    33 {
    34 public:
    35     Message(TaskThread* mb);
    36 };
    37 
    38 Message::Message(TaskThread* mb)
    39 {
    40     for (int i = 0;i < 6;++i)
    41     {
    42         string m_data = g_strMsg[i];
    43         ACE_Message_Block* msg = new ACE_Message_Block(sizeof(m_data));
    44         msg->copy(m_data.c_str());
    45         mb->putq(msg);    //put
    46     }
    47 }
    48 
    49 int main(int argc, char *argv[]) 
    50 { 
    51     TaskThread task;
    52     Message initMsg(&task);
    53     task.activate(THR_NEW_LWP | THR_JOINABLE |THR_INHERIT_SCHED , 10);//创建10个线程
    54     while(1);
    55     return 0; 
    56 }

    修改线程数量进行测试:

    10个线程效果:

    3个线程效果:

     

    1个线程效果:

    有了这个ACE_TASK的demo,我们跟踪查看ACE源码。

    在Task.cpp的ACE_Task_Base内的activate函数,可以看到线程是怎么创建出来的。

      1 int
      2 ACE_Task_Base::activate (long flags,
      3                          int n_threads,
      4                          int force_active,
      5                          long priority,
      6                          int grp_id,
      7                          ACE_Task_Base *task,
      8                          ACE_hthread_t thread_handles[],
      9                          void *stack[],
     10                          size_t stack_size[],
     11                          ACE_thread_t thread_ids[],
     12                          const char* thr_name[])
     13 {
     14   ACE_TRACE ("ACE_Task_Base::activate");
     15 
     16 #if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0)
     17   ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -1);
     18 
     19   // If the task passed in is zero, we will use <this>
     20   if (task == 0)
     21     task = this;
     22 
     23   if (this->thr_count_ > 0 && force_active == 0)
     24     return 1; // Already active.
     25   else
     26     {
     27       if (this->thr_count_ > 0 && this->grp_id_ != -1)
     28         // If we're joining an existing group of threads then make
     29         // sure to use its group id.
     30         grp_id = this->grp_id_;
     31       this->thr_count_ += n_threads;
     32     }
     33 
     34   // Use the ACE_Thread_Manager singleton if we're running as an
     35   // active object and the caller didn't supply us with a
     36   // Thread_Manager.
     37   if (this->thr_mgr_ == 0)
     38 # if defined (ACE_THREAD_MANAGER_LACKS_STATICS)
     39     this->thr_mgr_ = ACE_THREAD_MANAGER_SINGLETON::instance ();
     40 # else /* ! ACE_THREAD_MANAGER_LACKS_STATICS */
     41     this->thr_mgr_ = ACE_Thread_Manager::instance ();
     42 # endif /* ACE_THREAD_MANAGER_LACKS_STATICS */
     43 
     44   int grp_spawned = -1;
     45   if (thread_ids == 0)
     46     // Thread Ids were not specified
     47     grp_spawned =
     48       this->thr_mgr_->spawn_n (n_threads,
     49                                &ACE_Task_Base::svc_run,
     50                                (void *) this,
     51                                flags,
     52                                priority,
     53                                grp_id,
     54                                task,
     55                                thread_handles,
     56                                stack,
     57                                stack_size,
     58                                thr_name);
     59   else
     60     // thread names were specified
     61     grp_spawned =
     62       this->thr_mgr_->spawn_n (thread_ids,
     63                                n_threads,
     64                                &ACE_Task_Base::svc_run,
     65                                (void *) this,
     66                                flags,
     67                                priority,
     68                                grp_id,
     69                                stack,
     70                                stack_size,
     71                                thread_handles,
     72                                task,
     73                                thr_name);
     74   if (grp_spawned == -1)
     75     {
     76       // If spawn_n fails, restore original thread count.
     77       this->thr_count_ -= n_threads;
     78       return -1;
     79     }
     80 
     81   if (this->grp_id_ == -1)
     82     this->grp_id_ = grp_spawned;
     83 
     84 #if defined (ACE_MVS) || defined(__TANDEM)
     85   ACE_OS::memcpy( &this->last_thread_id_, '', sizeof(this->last_thread_id_));
     86 #else
     87   this->last_thread_id_ = 0;    // Reset to prevent inadvertant match on ID
     88 #endif /* defined (ACE_MVS) */
     89 
     90   return 0;
     91 
     92 #else
     93   {
     94     // Keep the compiler from complaining.
     95     ACE_UNUSED_ARG (flags);
     96     ACE_UNUSED_ARG (n_threads);
     97     ACE_UNUSED_ARG (force_active);
     98     ACE_UNUSED_ARG (priority);
     99     ACE_UNUSED_ARG (grp_id);
    100     ACE_UNUSED_ARG (task);
    101     ACE_UNUSED_ARG (thread_handles);
    102     ACE_UNUSED_ARG (stack);
    103     ACE_UNUSED_ARG (stack_size);
    104     ACE_UNUSED_ARG (thread_ids);
    105     ACE_UNUSED_ARG (thr_name);
    106     ACE_NOTSUP_RETURN (-1);
    107   }
    108 #endif /* ACE_MT_SAFE */
    109 }

    第49行,把线程执行函数指向了svc_run。

     1 ACE_THR_FUNC_RETURN
     2 ACE_Task_Base::svc_run (void *args)
     3 {
     4   ACE_TRACE ("ACE_Task_Base::svc_run");
     5 
     6   ACE_Task_Base *t = (ACE_Task_Base *) args;
     7 
     8   // Register ourself with our <Thread_Manager>'s thread exit hook
     9   // mechanism so that our close() hook will be sure to get invoked
    10   // when this thread exits.
    11 
    12 #if defined ACE_HAS_SIG_C_FUNC
    13   t->thr_mgr ()->at_exit (t, ACE_Task_Base_cleanup, 0);
    14 #else
    15   t->thr_mgr ()->at_exit (t, ACE_Task_Base::cleanup, 0);
    16 #endif /* ACE_HAS_SIG_C_FUNC */
    17 
    18   // Call the Task's svc() hook method.
    19   int const svc_status = t->svc ();
    20   ACE_THR_FUNC_RETURN status;
    21 #if defined (ACE_HAS_INTEGRAL_TYPE_THR_FUNC_RETURN)
    22   // Reinterpret case between integral types is not mentioned in the C++ spec
    23   status = static_cast<ACE_THR_FUNC_RETURN> (svc_status);
    24 #else
    25   status = reinterpret_cast<ACE_THR_FUNC_RETURN> (svc_status);
    26 #endif /* ACE_HAS_INTEGRAL_TYPE_THR_FUNC_RETURN */
    27 
    28 // If we changed this zero change the other if in OS.cpp Thread_Adapter::invoke
    29 #if 1
    30   // Call the <Task->close> hook.
    31   ACE_Thread_Manager *thr_mgr_ptr = t->thr_mgr ();
    32 
    33   // This calls the Task->close () hook.
    34   t->cleanup (t, 0);
    35 
    36   // This prevents a second invocation of the cleanup code
    37   // (called later by <ACE_Thread_Manager::exit>.
    38   thr_mgr_ptr->at_exit (t, 0, 0);
    39 #endif
    40   return status;
    41 }

    svc_run则在第19行调用了具体的我们在外部重写的虚函数函数执行。

    下面是消息队列的维护,putq和getq在内联函数文件Task_T.inl内。

     1 template <ACE_SYNCH_DECL> ACE_INLINE int
     2 ACE_Task<ACE_SYNCH_USE>::getq (ACE_Message_Block *&mb, ACE_Time_Value *tv)
     3 {
     4   ACE_TRACE ("ACE_Task<ACE_SYNCH_USE>::getq");
     5   return this->msg_queue_->dequeue_head (mb, tv);
     6 }
     7 
     8 template <ACE_SYNCH_DECL> ACE_INLINE int
     9 ACE_Task<ACE_SYNCH_USE>::putq (ACE_Message_Block *mb, ACE_Time_Value *tv)
    10 {
    11   ACE_TRACE ("ACE_Task<ACE_SYNCH_USE>::putq");
    12   return this->msg_queue_->enqueue_tail (mb, tv);
    13 }

    实则就是在维护ACE_Task类里面的ACE_Message_Queue<ACE_SYNCH_USE> *msg_queue_;这个队列。

    ACE_Task相对简单,里面关于线程池的创建和调度还是有很多值得学习的地方。

  • 相关阅读:
    材料订单不在IN_MO或者IN_SCFHEADER中
    FP ABPPMGR表 其它常用存储过程
    ORA-01578 ORACLE data block corrupted (file # 29, block # 2889087)
    PR合并回写
    MySQL优化
    分享一些JVM常见的面试题(转)
    怎么保证 redis 和 db 中的数据一致
    User space(用户空间) 与 Kernel space(内核空间)
    如何设计一个安全的对外接口?(转)
    Jstack命令详解
  • 原文地址:https://www.cnblogs.com/binchen-china/p/5614275.html
Copyright © 2020-2023  润新知