freeswitch的任务引擎实现分析

 

概述

freeswitch核心框架中有一个定时任务系统,在开发过程中用来做一些延时操作和异步操作很方便。

我们在VOIP的呼叫流程中,经常会有一些对实时性要求没那么高的操作,或者会有阻塞流程的操作,我们都可以开启一个定时任务子流程,来达到延时和异步的目标。

下面,我们来对这个任务引擎的代码实现做一个简单的梳理和分析。

环境

centos:CentOS  release 7.0 (Final)或以上版本

freeswitch:v1.8.7

GCC:4.8.5

数据结构

源码文件

src\include\switch_scheduler.h

src\switch_scheduler.c

任务数据结构

struct switch_scheduler_task {

       int64_t created;

       int64_t runtime;

       uint32_t cmd_id;

       uint32_t repeat;

       char *group;

       void *cmd_arg;

       uint32_t task_id;

       unsigned long hash;

};

struct switch_scheduler_task_container {

       switch_scheduler_task_t task;

       int64_t executed;

       int in_thread;

       int destroyed;

       int running;

       switch_scheduler_func_t func;

       switch_memory_pool_t *pool;

       uint32_t flags;

       char *desc;

       struct switch_scheduler_task_container *next;

};

typedef struct switch_scheduler_task_container switch_scheduler_task_container_t;

static struct {

       switch_scheduler_task_container_t *task_list;

       switch_mutex_t *task_mutex;

       uint32_t task_id;

       int task_thread_running;

       switch_queue_t *event_queue;

       switch_memory_pool_t *memory_pool;

} globals;

总图

 

常用接口

查看src\include\switch_scheduler.h头文件,常用接口如下。

switch_scheduler_add_task  //Schedule a task in the future

switch_scheduler_del_task_id      //Delete a scheduled task

switch_scheduler_del_task_group       //Delete a scheduled task based on the group name

switch_scheduler_task_thread_start    //Start the scheduler system

switch_scheduler_task_thread_stop    //Stop the scheduler system

外部接口很简单。初始化接口使用start和stop,新增任务使用add_task,删除任务使用del_task_id,另外有一个del_task_group的接口针对任务群。

引擎初始化switch_scheduler_task_thread_start

函数原型

SWITCH_DECLARE(void) switch_scheduler_task_thread_start(void);

函数逻辑:

  1. 初始化内存池globals.memory_pool。
  2. 初始化互斥锁globals.task_mutex。
  3. 初始化消息队列globals.event_queue。
  4. 创建任务执行线程,线程函数switch_scheduler_task_thread,以下是任务线程的逻辑流程。
  5. 设置全局变量globals.task_thread_running = 1。
  6. 任务线程循环开始,task_thread_loop(0)。
  7. 加锁globals.task_mutex。
  8. 遍历任务链表globals.task_list,检查任务执行时间,符合执行时间的任务检查线程标识,对于有单独线程标识SSHF_OWN_THREAD的任务启动线程task_own_thread并执行,对于没有单独线程标识的任务,在当前线程中执行。
  9. 解锁globals.task_mutex。
  10. 加锁globals.task_mutex。
  11. 遍历任务链表globals.task_list,检查任务删除标识tp->destroyed,销毁任务,释放任务相关内存。
  12. 解锁globals.task_mutex。
  13. 从全局消息队列globals.event_queue中获取事件,并发布该事件。
  14. 任务线程循环结束。
  15. task_thread_loop(1),遍历任务链表globals.task_list,设置所有任务删除标识tp->destroyed = 1,销毁任务,释放任务相关内存。
  16. 从全局消息队列globals.event_queue中获取事件并销毁。
  17. 设置全局变量globals.task_thread_running = 0。

引擎初始化后的内存模型如图

 

引擎停止switch_scheduler_task_thread_stop

函数原型

SWITCH_DECLARE(void) switch_scheduler_task_thread_stop(void);

函数逻辑:

  1. 设置全局变量globals.task_thread_running=-1。
  2. 等待任务线程退出。
  3. 销毁内存池globals.memory_pool。

新增任务switch_scheduler_add_task

函数原型

SWITCH_DECLARE(uint32_t) switch_scheduler_add_task(time_t task_runtime,

                                                                                       switch_scheduler_func_t func,

                                                                                       const char *desc, const char *group, uint32_t cmd_id, void *cmd_arg, switch_scheduler_flag_t flags);

函数逻辑:

  1. 加锁globals.task_mutex。
  2. 分配一块内存给任务容器container,类型为switch_scheduler_task_container_t。
  3. container数据初始化。包括回调函数func和任务预定运行时间等信息。
  4. 将container插入任务链表globals.task_list的队尾。
  5. 解锁globals.task_mutex。
  6. 新建SWITCH_EVENT_ADD_SCHEDULE事件,并将事件插入消息队列globals.event_queue。
  7. 结束返回任务id。

增加多个任务之后的内存模型如图

 

删除任务switch_scheduler_del_task_id

函数原型

SWITCH_DECLARE(uint32_t) switch_scheduler_del_task_id(uint32_t task_id);

函数逻辑:

  1. 加锁globals.task_mutex。
  2. 遍历任务链表globals.task_list,找到对应task_id的任务。
  3. 任务标识SSHF_NO_DEL则不删除。
  4. 任务正在运行则不删除。
  5. 设置任务删除标识tp->destroyed++。
  6. 解锁globals.task_mutex。

总结

任务引擎中的循环,在任务执行正常的情况下,每隔500ms检查1次任务链表,在实际应用中,可能会有一定的延迟,无法做到实时执行。

对于任务的执行过程,考虑到有阻塞操作的任务,一定要使用单独线程执行,否则会阻塞其他任务。

定时任务引擎,使用时间轮模式是否更好用?

空空如常

求真得真

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值