ACE - ACE_Task源码剖析及线程池实现
原文出自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通道过来的数据都要以单线程的方式执行业务,效率就非常低了。必须当线程空闲时才能占有,所以这里有必要引入线程池去处理业务。

ACE_Task类封装了线程和消息队列,使这些功能以面向对象的方式提供给用户,其中消息队列并非IPC中的消息队列,在ACE实现实际为普通队列。利用ACE_Task可以生产一个或一组线程,并且为线程池之间的消息交互提供了接口和队列。在Event部分,我们可以利用线程池来解决效率问题。
下面提供线程池实现代码:
#include "ace/Task.h"
#include "ace/OS.h"
#include <string> using namespace std; string g_strMsg[] = {
"MESSAGE 1",
"MESSAGE 2",
"MESSAGE 3",
"MESSAGE 4",
"MESSAGE 5",
"MESSAGE 6",
}; class TaskThread: public ACE_Task<ACE_MT_SYNCH>
{
public:
virtual int svc(void)
{
ACE_Message_Block *Msg;// = new ACE_Message_Block();
while()
{
getq(Msg); //空闲线程阻塞
ACE_DEBUG((LM_INFO,"recevie msg:%s,time:%d\n",Msg->rd_ptr(),(int)ACE_OS::time()));
Msg->release(); //release
ACE_OS::sleep(); //延时1s模拟业务处理耗时
}
}
}; class Message
{
public:
Message(TaskThread* mb);
}; Message::Message(TaskThread* mb)
{
for (int i = ;i < ;++i)
{
string m_data = g_strMsg[i];
ACE_Message_Block* msg = new ACE_Message_Block(sizeof(m_data));
msg->copy(m_data.c_str());
mb->putq(msg); //put
}
} int main(int argc, char *argv[])
{
TaskThread task;
Message initMsg(&task);
task.activate(THR_NEW_LWP | THR_JOINABLE |THR_INHERIT_SCHED , );//创建10个线程
while();
return ;
}
修改线程数量进行测试:
10个线程效果:

3个线程效果:

1个线程效果:

有了这个ACE_TASK的demo,我们跟踪查看ACE源码。
在Task.cpp的ACE_Task_Base内的activate函数,可以看到线程是怎么创建出来的。
int
ACE_Task_Base::activate (long flags,
int n_threads,
int force_active,
long priority,
int grp_id,
ACE_Task_Base *task,
ACE_hthread_t thread_handles[],
void *stack[],
size_t stack_size[],
ACE_thread_t thread_ids[],
const char* thr_name[])
{
ACE_TRACE ("ACE_Task_Base::activate"); #if defined (ACE_MT_SAFE) && (ACE_MT_SAFE != 0)
ACE_GUARD_RETURN (ACE_Thread_Mutex, ace_mon, this->lock_, -); // If the task passed in is zero, we will use <this>
if (task == )
task = this; if (this->thr_count_ > && force_active == )
return ; // Already active.
else
{
if (this->thr_count_ > && this->grp_id_ != -)
// If we're joining an existing group of threads then make
// sure to use its group id.
grp_id = this->grp_id_;
this->thr_count_ += n_threads;
} // Use the ACE_Thread_Manager singleton if we're running as an
// active object and the caller didn't supply us with a
// Thread_Manager.
if (this->thr_mgr_ == )
# if defined (ACE_THREAD_MANAGER_LACKS_STATICS)
this->thr_mgr_ = ACE_THREAD_MANAGER_SINGLETON::instance ();
# else /* ! ACE_THREAD_MANAGER_LACKS_STATICS */
this->thr_mgr_ = ACE_Thread_Manager::instance ();
# endif /* ACE_THREAD_MANAGER_LACKS_STATICS */ int grp_spawned = -;
if (thread_ids == )
// Thread Ids were not specified
grp_spawned =
this->thr_mgr_->spawn_n (n_threads,
&ACE_Task_Base::svc_run,
(void *) this,
flags,
priority,
grp_id,
task,
thread_handles,
stack,
stack_size,
thr_name);
else
// thread names were specified
grp_spawned =
this->thr_mgr_->spawn_n (thread_ids,
n_threads,
&ACE_Task_Base::svc_run,
(void *) this,
flags,
priority,
grp_id,
stack,
stack_size,
thread_handles,
task,
thr_name);
if (grp_spawned == -)
{
// If spawn_n fails, restore original thread count.
this->thr_count_ -= n_threads;
return -;
} if (this->grp_id_ == -)
this->grp_id_ = grp_spawned; #if defined (ACE_MVS) || defined(__TANDEM)
ACE_OS::memcpy( &this->last_thread_id_, '\0', sizeof(this->last_thread_id_));
#else
this->last_thread_id_ = ; // Reset to prevent inadvertant match on ID
#endif /* defined (ACE_MVS) */ return ; #else
{
// Keep the compiler from complaining.
ACE_UNUSED_ARG (flags);
ACE_UNUSED_ARG (n_threads);
ACE_UNUSED_ARG (force_active);
ACE_UNUSED_ARG (priority);
ACE_UNUSED_ARG (grp_id);
ACE_UNUSED_ARG (task);
ACE_UNUSED_ARG (thread_handles);
ACE_UNUSED_ARG (stack);
ACE_UNUSED_ARG (stack_size);
ACE_UNUSED_ARG (thread_ids);
ACE_UNUSED_ARG (thr_name);
ACE_NOTSUP_RETURN (-);
}
#endif /* ACE_MT_SAFE */
}
第49行,把线程执行函数指向了svc_run。
ACE_THR_FUNC_RETURN
ACE_Task_Base::svc_run (void *args)
{
ACE_TRACE ("ACE_Task_Base::svc_run"); ACE_Task_Base *t = (ACE_Task_Base *) args; // Register ourself with our <Thread_Manager>'s thread exit hook
// mechanism so that our close() hook will be sure to get invoked
// when this thread exits. #if defined ACE_HAS_SIG_C_FUNC
t->thr_mgr ()->at_exit (t, ACE_Task_Base_cleanup, );
#else
t->thr_mgr ()->at_exit (t, ACE_Task_Base::cleanup, );
#endif /* ACE_HAS_SIG_C_FUNC */ // Call the Task's svc() hook method.
int const svc_status = t->svc ();
ACE_THR_FUNC_RETURN status;
#if defined (ACE_HAS_INTEGRAL_TYPE_THR_FUNC_RETURN)
// Reinterpret case between integral types is not mentioned in the C++ spec
status = static_cast<ACE_THR_FUNC_RETURN> (svc_status);
#else
status = reinterpret_cast<ACE_THR_FUNC_RETURN> (svc_status);
#endif /* ACE_HAS_INTEGRAL_TYPE_THR_FUNC_RETURN */ // If we changed this zero change the other if in OS.cpp Thread_Adapter::invoke
#if 1
// Call the <Task->close> hook.
ACE_Thread_Manager *thr_mgr_ptr = t->thr_mgr (); // This calls the Task->close () hook.
t->cleanup (t, ); // This prevents a second invocation of the cleanup code
// (called later by <ACE_Thread_Manager::exit>.
thr_mgr_ptr->at_exit (t, , );
#endif
return status;
}
svc_run则在第19行调用了具体的我们在外部重写的虚函数函数执行。
下面是消息队列的维护,putq和getq在内联函数文件Task_T.inl内。
template <ACE_SYNCH_DECL> ACE_INLINE int
ACE_Task<ACE_SYNCH_USE>::getq (ACE_Message_Block *&mb, ACE_Time_Value *tv)
{
ACE_TRACE ("ACE_Task<ACE_SYNCH_USE>::getq");
return this->msg_queue_->dequeue_head (mb, tv);
} template <ACE_SYNCH_DECL> ACE_INLINE int
ACE_Task<ACE_SYNCH_USE>::putq (ACE_Message_Block *mb, ACE_Time_Value *tv)
{
ACE_TRACE ("ACE_Task<ACE_SYNCH_USE>::putq");
return this->msg_queue_->enqueue_tail (mb, tv);
}
实则就是在维护ACE_Task类里面的ACE_Message_Queue<ACE_SYNCH_USE> *msg_queue_;这个队列。
ACE_Task相对简单,里面关于线程池的创建和调度还是有很多值得学习的地方。
ACE - ACE_Task源码剖析及线程池实现的更多相关文章
- 源码剖析ThreadPoolExecutor线程池及阻塞队列
本文章对ThreadPoolExecutor线程池的底层源码进行分析,线程池如何起到了线程复用.又是如何进行维护我们的线程任务的呢?我们直接进入正题: 首先我们看一下ThreadPoolExecuto ...
- 【高并发】通过ThreadPoolExecutor类的源码深度解析线程池执行任务的核心流程
核心逻辑概述 ThreadPoolExecutor是Java线程池中最核心的类之一,它能够保证线程池按照正常的业务逻辑执行任务,并通过原子方式更新线程池每个阶段的状态. ThreadPoolExecu ...
- Java并发包源码学习之线程池(一)ThreadPoolExecutor源码分析
Java中使用线程池技术一般都是使用Executors这个工厂类,它提供了非常简单方法来创建各种类型的线程池: public static ExecutorService newFixedThread ...
- SOFA 源码分析 — 自定义线程池原理
前言 在 SOFA-RPC 的官方介绍里,介绍了自定义线程池,可以为指定服务设置一个独立的业务线程池,和 SOFARPC 自身的业务线程池是隔离的.多个服务可以共用一个独立的线程池. API使用方式如 ...
- 深入源码分析Java线程池的实现原理
程序的运行,其本质上,是对系统资源(CPU.内存.磁盘.网络等等)的使用.如何高效的使用这些资源是我们编程优化演进的一个方向.今天说的线程池就是一种对CPU利用的优化手段. 通过学习线程池原理,明白所 ...
- 源码分析—ThreadPoolExecutor线程池三大问题及改进方案
前言 在一次聚会中,我和一个腾讯大佬聊起了池化技术,提及到java的线程池实现问题,我说这个我懂啊,然后巴拉巴拉说了一大堆,然后腾讯大佬问我说,那你知道线程池有什么缺陷吗?我顿时哑口无言,甘拜下风,所 ...
- Netty源码解析一——线程池模型之线程池NioEventLoopGroup
本文基础是需要有Netty的使用经验,如果没有编码经验,可以参考官网给的例子:https://netty.io/wiki/user-guide-for-4.x.html.另外本文也是针对的是Netty ...
- 从JDK源码角度看线程池原理
"池"技术对我们来说是非常熟悉的一个概念,它的引入是为了在某些场景下提高系统某些关键节点性能,最典型的例子就是数据库连接池,JDBC是一种服务供应接口(SPI),具体的数据库连接实 ...
- MYSQL 源码解读系列 [线程池。。] ----dennis的博客
http://blog.sina.com.cn/s/articlelist_1182000643_0_1.html
随机推荐
- Linux Shell 文本处理工具集锦
本文将介绍Linux下使用Shell处理文本时最常用的工具:find.grep.xargs.sort.uniq.tr.cut.paste.wc.sed.awk:提供的例子和参数都是最常用和最为实用的: ...
- linux下启动AP热点时出错
1.启动hostapd,在终端下输入sudo ./hostapd hostapd.conf (注意:使用到的hostapd和hostapd.conf都处在当前工作目录下) 1.2.在执行1之后会出现以 ...
- Caffe + Ubuntu 14.04 64bit + CUDA6.5 + 无GPU 配置
官网: http://caffe.berkeleyvision.org/installation.html#compilation 参考网站: http://www.cnblogs.com/dupul ...
- XAF响应式布局皮肤界面展示
XAF为了对手机.平板电脑的支持,增加了新的响应式布局皮肤支持,这个功能已经出来很久了,对于平板电脑.PC的支持已经很不错了,对于手机的界面还不是很完美. 本篇展示一下当前的效果,让有需要的同学.还没 ...
- 转 猫都能学会的Unity3D Shader入门指南(二)
猫都能学会的Unity3D Shader入门指南(二) 关于本系列 这是Unity3D Shader入门指南系列的第二篇,本系列面向的对象是新接触Shader开发的Unity3D使用者,因为我本身自己 ...
- 网络基础知识之————A记录和CNAME记录的区别
1.什么是域名解析? 域名解析就是国际域名或者国内域名以及中文域名等域名申请后做的到IP地址的转换过程.IP地址是网路上标识您站点的数字地址,为了简单好记,采用域名来代替ip地址标识站点地址.域名的解 ...
- nodejs 访问mysql
安装 $ npm install mysql 简介 这个一个mysql的nodejs版本的驱动,是用JavaScript来编写的.不需要编译 这儿有个例子来示范如何使用: var mysql = re ...
- 程序设计入门——C语言 第5周编程练习 1高精度小数(10分)
1 高精度小数(10分) 题目内容: 由于计算机内部表达方式的限制,浮点运算都有精度问题,为了得到高精度的计算结果,就需要自己设计实现方法. (0,1)之间的任何浮点数都可以表达为两个正整数的商,为了 ...
- Shell 语法之结构化命令(流程控制)
许多程序在脚本命令之间需要某种逻辑流控制,允许脚本根据变量值的条件或者其他命令的结果路过一些命令或者循环执行这些命令.这些命令通常被称为结构化命令.和其他高级程序设计语言一样,shell提供了用来控制 ...
- Android Studio教程从入门到精通
最新2.0系列文章参考: Android Studio2.0 教程从入门到精通Windows版 - 安装篇Android Studio2.0 教程从入门到精通Windows版 - 入门篇Android ...