基本原理 -

在chaos开篇介绍(http://www.cppthinker.com/chaos/57/chaos_1)中已经提到,task service作为chaos库的核心,主要承担着三个重则:

1. 网络I/O

2. 超时事件

3. 异步消息处理

简单来讲,可以认为一个task service中包含一个epollfd,一个定时事件管理器,一个等待被处理的异步消息队列

而task service会有一个主循环来周而复始地执行这些任务(单线程 or 多线程,后续篇章再做分析),如图:

注意: task service总是优先处理I/O事件,因为通常I/O事件都会牵涉到与用户的交互,所以我们希望尽可能快地响应用户

基本实现 -

对于I/O事件 和 超时事件 这里不想熬述太多,I/O事件的处理无非就是利用底层的网络复用模型(例如epoll)返回响应的fd然后回调,而超时事件的管理网上也有诸多方法,这里task service采用的是std::priority_queue(堆结构),每次tick都会从堆中拿出最近事件来检查是否超时

我们直接来关注异步消息的处理是如何实现的:

异步消息处理的关键在于:我们如何制定一个通用的“异步消息体”,让我们的task service看起来这些消息体都是等同的,都是可执行的元素,但现实总是那么的残酷,通常我们总需要执行不同的任务,调用不同的函数,传递不同的参数类型和参数个数

很多动态语言可以通过closure(闭包)来实现这一步,其实c++也可以,首先让我们先来整理一下我们的需求:

我们需要一个closure来打包我们的异步请求(函数和参数)

1. 它必须包含一个任何声明类型的函数执行体(函数指针)

2. 它可以装入任何类型的参数

3. 它可以装入任意个数的参数

对于需求1,我们有模板

对于需求2,我们有模板

对于需求3,我们有函数重载

是的,函数重载,但你一定会问,函数重载只能指定有限个参数,没错,我们一般只要提供最多10个左右的参数的函数重载就行了,毕竟谁会写出那么不结构化的代码,想向一个函数传入十几个以上的参数,如果有,那么ta一定会被后续的维护人员牵肠挂肚。

我们直接来看chaos中实现:

template<typename FUNC, typename ARG0>
class async_method_bind_func_1_t: public async_method_base_t
{
public:async_method_bind_func_1_t(): m_func1(NULL){   }   async_method_bind_func_1_t(FUNC func_, const ARG0& arg0_): m_func1(func_),m_arg0(arg0_){   }   virtual void exec(){   (*m_func1)(m_arg0);}   private:FUNC            m_func1;ARG0            m_arg0;
};

以上就是我们实现的一个闭包,包含了一个模板函数的指针,包含了一个模板参数(要支持多个参数只需编写多个重载接口即可),当调用exec函数时,该闭包就会被执行

OK,这个问题是否已经被解决了?不,还没有,c++中存在着两种函数,一种是和对象无关的(全局/静态),一种是和对象有关的(成员函数),我们上面只是解决了和对象无关的函数,接下来我们来看如何解决对象成员函数的打包

template<typename T, typename FUNC, typename ARG0>
class async_method_bind_obj_1_t: public async_method_base_t
{
public:async_method_bind_obj_1_t(){   }   async_method_bind_obj_1_t(T instance_, FUNC func1_, const ARG0& arg0_): m_instance(instance_),m_func1(func1_),m_arg0(arg0_){   }   virtual void exec(){   (m_instance->*m_func1)(m_arg0);}   private:T           m_instance;FUNC        m_func1;ARG0        m_arg0;
};

我们只需多保存一个对象实例的地址,就能调用到其构造函数

这两种实现方法都是继承自同一个基类,那么对于task service来说,就有了统一的异步消息体的抽象,外界只要通过接口生成不同的async_method_base_t实例,然后投入到task service的队列中,task service就能完成对这些异步消息的执行

接口使用 -

task service的使用也很简单,对于我们上述的三种事件的处理,task service分别提供了三种不同的接口来供你注册

class task_service_t : private noncopyable_t
{
public:
...
...
void register_io_event(fd_t                    fd_,int                     event_type_flag_,callback_on_event_t     callback_       = NULL,void*                   cb_arg_         = NULL,bool                    is_persist_     = false);
void register_timer(uint32_t                        interval_,const time_event_callback_t&    callback_,bool                            persist_ = false,time_t                          start_time_ = 0 );
int post(const async_method_t& async_method_,void* ext_data_ = NULL,task_prior_e prior_ = TASK_PRIOR_NORMAL,bool is_allow_exec_local_ = true);
...
...
};

这三个方法分别代表 注册一个I/O监听事件,注册一个超时事件,投递一个异步消息

我们接下来看如何绑定一个异步消息

//! 绑定一个全局/静态函数,并投递到task service中执行
task_service.post(async_method_t::bind_func(&test_static_func, tmp_str));          //! 绑定一个类中的静态函数,并投递到task service中执行
task_service.post(async_method_t::bind_func(&foo_t::test_static_func, tmp_str));//! 绑定一个对象的成员函数,并投递到task service中执行
task_service.post(async_method_t::bind_memfunc(&hw, &hw_t::call1, 123456));

PS:chaos中的async_method实现相比boost::function以及c++ 11中的std::bind都要少很多功能,我不使用它们而自己实现的原因在于

1. 不想引入庞大的boost库

2. 不希望chaos依赖于高版本的c++标准库

3. 我希望实现一个轻量级的,足以封装异步消息的类,而不用像boost::function那样做得面面俱到(话说回来boost::function确实很逆天:))

chaos库的task service我就先讲到这,之后我们再写一篇关于task service进阶的一些使用和注意细节

task service和async method的完整源代码大家可到

https://github.com/lyjdamzwf/chaos/tree/master/chaos/task_service

https://github.com/lyjdamzwf/chaos/tree/master/chaos/async_method

下载

我的个人博客地址:www.thinker.com

欢迎大家交流:)

转载于:https://www.cnblogs.com/emperor_zark/archive/2012/12/11/chaos_task_service.html

Chaos网络库(三)- 主循环及异步消息的实现相关推荐

  1. 《Linux多线程服务端编程:使用muduo C++网络库》书摘6.6.2节

    6.6.2 常见的并发网络服务程序设计方案 W. Richard Stevens 的<UNIX 网络编程(第2 版)>第27 章"Client-ServerDesign Alte ...

  2. C++练手项目(基于muduo网络库+mysql+jsoncpp的简易HTTPWebServer用于网页显示数据库后台数据

    基于muduo网络库+mysql+jsoncpp的简易HTTPWebServer 项目介绍 背景介绍 主要模块介绍 1.基于muduo网络库的WebServer: 2.HTTP协议栈 3.JsonSe ...

  3. muduo网络库学习(四)事件驱动循环EventLoop

    muduo的设计采用高并发服务器框架中的one loop per thread模式,即一个线程一个事件循环. 这里的loop,其实就是muduo中的EventLoop,所以到目前为止,不管是Polle ...

  4. muduo网络库学习(八)事件驱动循环线程池EventLoopThreadPool

    muduo是支持多线程的网络库,在muduo网络库学习(七)用于创建服务器的类TcpServer中也提及了TcpServer中有一个事件驱动循环线程池,线程池中存在大量线程,每个线程运行一个Event ...

  5. muduo网络库学习(三)定时器TimerQueue的设计

    Linux下用于获取当前时间的函数有 time(2) / time_t (秒) ftime(3) / struct timeb (毫秒) gettimeofday(2) / struct timeva ...

  6. 一图看懂 aiohttp 模块:基于 asyncio 的异步HTTP网络库, 资料整理+笔记(大全)

    本文由 大侠(AhcaoZhu)原创,转载请声明. 链接: https://blog.csdn.net/Ahcao2008 一图看懂 aiohttp 模块:基于 asyncio 的异步HTTP网络库, ...

  7. muduo网络库:09---多线程服务器之(单线程、多线程服务器的适用场合)

    本文内容衔接于前一篇文章(进程间通信只用TCP):https://blog.csdn.net/qq_41453285/article/details/104997453 一.服务器开发概述 " ...

  8. 基于C++11的muduo网络库

    文章目录 写在前面 项目编译问题 库安装的问题 项目测试代码 关于压力测试 项目概述 muduo网络库的reactor模型 muduo的设计 muduo各个类 辅助类 NonCopyable Time ...

  9. 网络库libevent、libev、libuv、libhv对比

    网络库libevent.libev.libuv对比_小麒麟的成长之路-CSDN博客_libevent libuv Libevent.libev.libuv三个网络库,都是c语言实现的异步事件库Asyn ...

最新文章

  1. 为 ActionScript 导出库元件
  2. bzoj2806: [Ctsc2012]Cheat
  3. 亚马逊AWS本月第三次出现数据中心断电故障,Coinbase、Slack等受影响
  4. SAP系统与外部系统的三种接口形式
  5. 【Java】二维码生成,QRcode
  6. Python、Perl 垫底,C语言才是最环保的编程语言
  7. 告毕业生书——七剑送你下天山
  8. mysql 插入数据 自增长_如何在MYSQL插数据 ID自增
  9. (二叉树的动态创建与bfs)树的层次遍历
  10. AIX5.3安装oracle10g
  11. Vue 3.0已进入发布候选阶段!
  12. 计算机网络基石 —— 集线器
  13. CentOS6.6安装cobbler
  14. Toontrack Superior Drummer for Mac(鼓音乐制作工具)
  15. eclipse运行java程序出现多个问题:内部错误IOConsole Updater
  16. Linux线程管理必备:互斥量与条件变量
  17. 数模更新篇-3-因子分析模型
  18. 计算机的储存容量1kb等于多少byte,1kb等于多少mb
  19. 单片机基础知识学习笔记
  20. 码栈开发手册(四)---编码方式开发(其他功能函数)

热门文章

  1. Web前端Javascript笔记(8)Ajax前后端交互
  2. VMware虚拟机中ubuntu的磁盘怎么扩容
  3. js图表报表html5图表,介绍一个!非常简单非常方便!制作图表报表的js库 —— ichartjs 【详细操作】...
  4. pythoncsv格式清洗与转换_数据预处理-清洗转换
  5. Python中的字符串(搜索和替换、对齐、统计、分离和连接)
  6. 写入多个表_制作属于自己的教学工作表
  7. 自动建议下拉菜单_word排版技巧:如何撤销删除自动编号
  8. 软件测试入门笔记(一)
  9. SAP License:如何做好ERP系统验收测试
  10. SAP License:SAP 各个模块含义