unimrcp源码窥探及task异步架构的学习(一)(Framework Agent)

2024-02-28 19:58

本文主要是介绍unimrcp源码窥探及task异步架构的学习(一)(Framework Agent),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

设置日志DEBUG级别,对照日志从main函数进入处理流程。必要时候用gdb工具单步执行调试。
一、task分析
了解task 的一切,从task创建开始。先来了解一下,apt_task_t这个结构体中包含了哪些数据。
  • 父task链表节点(注释的说法是这样的)  link
说明,环(ring)是一种双向链表,可以在不知道其头部在哪里的情况下进行操作。APR中的环的介绍,请看另外一篇文章的详解。
定义如下:      
APR_RING_ENTRY(apt_task_t) link;                 /* entry to parent task ring */
APR_RING_ENTRY是一个宏定义,按照宏定义展开的话,以上的定义是这样的结构:
struct {                               \
struct apt_task_t * volatile next;  \
struct apt_task_t * volatile prev;  \
}link;
由此可见,link为我们记录了访问父task链表的入口节点。
  • 子task的链表头(按照注释的理解) head
APR_RING_HEAD(apt_task_head_t, apt_task_t) head; /* head of child tasks ring */
我们把APR_RING_HEAD的宏定义展开,得到实际的结构:
struct apt_task_head_t {                            \
struct apt_task_t * volatile next;                    \
struct apt_task_t * volatile prev;                    \
}head;
  • 无类型指针 obj
obj是与任务关联的外部对象
  • 消息池   msg_pool
  • 互斥锁 data_guard
  • 虚方法表结构 vtable
虚方法表结构中有三类函数指针:
task的方法,  start/ run/ terminate/destroy方法
消息处理的有关方法, 发信号消息处理( signal_msg) 、消息处理( process_msg)、消息处理启动( process_start)、消息处理终止( process_terminate)
事件处理的有关方法, pre_run / post_run/  on_ start_complete / on_ terminate_complete/ on_offline_complete / on_online_complete  
红色标注的三个方法,在 apt_task_create函数中分别进行了赋值,由此可见他们是所有task通用的方法,没有自定义:
task->vtable. terminate= apt_task_terminate_request;
task->vtable. process_start= apt_task_start_process_internal;
task->vtable. process_terminate= apt_task_terminate_process_internal;
二、task实体
那么分析完apt_task_t以后,我们来解剖一下umc客户端,看看运行这样一个程序需要启动的task实体类型。
1. Framework Agent
配置类型?  对应的是UmcFramework的实例
最外层这个大的Agent,定义了UmcFramework这个类来进行管理。
重点关注m_pTask(apt_consumer_task_t*)变量 、m_pMrcpClient(mrcp_client_t*)变量和m_pMrcpApplication变量(mrcp_application_t*)
下面对此进行分解。首先是拿m_pTask来讲一下。
①创建task  对应的函数是UmcFramework::CreateTask()
先调用apt_consumer_task_create去创建一个consumer_task结构,在这创建的过程中,首先就要创建apt_task_t的结构,并将apt_task_t作为成员变量(base)存放于apt_consumer_task_t结构中。
②虚方法表中的 run方法、 signal_msg方法,在此处被定义赋值,既然是使用的 consumer,自然run方法和 singal_msg方法是跟consumer强关联的:
static apt_bool_t apt_consumer_task_msg_signal(apt_task_t *task, apt_task_msg_t *msg);
static apt_bool_t apt_consumer_task_run(apt_task_t *task);
这儿两个函数指针实例化,体现的正好是生产者/消费者模型。注意,不要跟apt_consumer_task_t的概念弄混淆。
signal后缀的函数,干一个事情,就是将一个apt_task_msg_t类型的消息,压入到消息队列中(生产)。
run后缀的函数,里面是一个无线循环,从消息队列中取消息,然后进行处理(消费)。具体实现上,要区分消息类型,根据消息种类不同(TASK_MSG_CORE/ TASK_MSG_USER),交给不同的函数去处理:
TASK_MSG_CORE类型的消息,是通过apt_task_msg_process去调用apt_core_task_msg_process函数进行处理
TASK_MSG_USER类型的消息,是通过apt_task_msg_process去调用process_msg这个函数指针,目前执行到这儿这个函数指针还没有实例化,是一个空指针。
处理完上述内容以后,回到CreateTask函数继续, 接下来拿到虚方法表结构,在这里先给 process_msg方法赋值,也就是上述生产者/消费者模型中,真正要处理TASK_MSG_USER消息的地方。
再把两个事件处理方法进行实现,就是 on_ start_complete方法和 on_ terminate_complete方法。
on_ start_complete方法会在 process_start执行的时候被调用到,
③最后一步,执行apt_task_start()函数,启动这个task!
默认是会再启一个线程执行启动操作的。线程中按照时间轴处理,流程是这样:
触发on_pre_run事件(当前该task没有定义该事件的触发)
修改task状态机
process_start处理    
  • 实际执行apt_task_start_process_internal函数
  • 从子任务队列中取出任务并执行(如果有)
  • 触发 on_ start_complete事件(没有子任务的情况下)
执行task
  • 虚方法表例的run方法,已用apt_consumer_task_run赋值
  • 无线循环,从消息池中取消息并消费消息
task退出运行,修改task状态机
触发on_post_run事件
Done!这样Framework Agent跑起来了!
写在最后:
 on_ start_complete事件中,完成了sip协议栈、mrcp协议栈的工作线程的创建和启动。详细可以见(二)中的解析。

这篇关于unimrcp源码窥探及task异步架构的学习(一)(Framework Agent)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/756464

相关文章

linux报错INFO:task xxxxxx:634 blocked for more than 120 seconds.三种解决方式

《linux报错INFO:taskxxxxxx:634blockedformorethan120seconds.三种解决方式》文章描述了一个Linux最小系统运行时出现的“hung_ta... 目录1.问题描述2.解决办法2.1 缩小文件系统缓存大小2.2 修改系统IO调度策略2.3 取消120秒时间限制3

如何使用celery进行异步处理和定时任务(django)

《如何使用celery进行异步处理和定时任务(django)》文章介绍了Celery的基本概念、安装方法、如何使用Celery进行异步任务处理以及如何设置定时任务,通过Celery,可以在Web应用中... 目录一、celery的作用二、安装celery三、使用celery 异步执行任务四、使用celery

Java汇编源码如何查看环境搭建

《Java汇编源码如何查看环境搭建》:本文主要介绍如何在IntelliJIDEA开发环境中搭建字节码和汇编环境,以便更好地进行代码调优和JVM学习,首先,介绍了如何配置IntelliJIDEA以方... 目录一、简介二、在IDEA开发环境中搭建汇编环境2.1 在IDEA中搭建字节码查看环境2.1.1 搭建步

Python使用asyncio实现异步操作的示例

《Python使用asyncio实现异步操作的示例》本文主要介绍了Python使用asyncio实现异步操作的示例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋... 目录1. 基础概念2. 实现异步 I/O 的步骤2.1 定义异步函数2.2 使用 await 等待异

C# Task Cancellation使用总结

《C#TaskCancellation使用总结》本文主要介绍了在使用CancellationTokenSource取消任务时的行为,以及如何使用Task的ContinueWith方法来处理任务的延... 目录C# Task Cancellation总结1、调用cancellationTokenSource.

Python中的异步:async 和 await以及操作中的事件循环、回调和异常

《Python中的异步:async和await以及操作中的事件循环、回调和异常》在现代编程中,异步操作在处理I/O密集型任务时,可以显著提高程序的性能和响应速度,Python提供了asyn... 目录引言什么是异步操作?python 中的异步编程基础async 和 await 关键字asyncio 模块理论

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

Ilya-AI分享的他在OpenAI学习到的15个提示工程技巧

Ilya(不是本人,claude AI)在社交媒体上分享了他在OpenAI学习到的15个Prompt撰写技巧。 以下是详细的内容: 提示精确化:在编写提示时,力求表达清晰准确。清楚地阐述任务需求和概念定义至关重要。例:不用"分析文本",而用"判断这段话的情感倾向:积极、消极还是中性"。 快速迭代:善于快速连续调整提示。熟练的提示工程师能够灵活地进行多轮优化。例:从"总结文章"到"用

mybatis的整体架构

mybatis的整体架构分为三层: 1.基础支持层 该层包括:数据源模块、事务管理模块、缓存模块、Binding模块、反射模块、类型转换模块、日志模块、资源加载模块、解析器模块 2.核心处理层 该层包括:配置解析、参数映射、SQL解析、SQL执行、结果集映射、插件 3.接口层 该层包括:SqlSession 基础支持层 该层保护mybatis的基础模块,它们为核心处理层提供了良好的支撑。

百度/小米/滴滴/京东,中台架构比较

小米中台建设实践 01 小米的三大中台建设:业务+数据+技术 业务中台--从业务说起 在中台建设中,需要规范化的服务接口、一致整合化的数据、容器化的技术组件以及弹性的基础设施。并结合业务情况,判定是否真的需要中台。 小米参考了业界优秀的案例包括移动中台、数据中台、业务中台、技术中台等,再结合其业务发展历程及业务现状,整理了中台架构的核心方法论,一是企业如何共享服务,二是如何为业务提供便利。