📌往期推文全新看点(文中附带最新·鸿蒙全栈学习笔记)
①📖 鸿蒙应用开发与鸿蒙系统开发哪个更有前景?
②📖嵌入式开发适不适合做鸿蒙南向开发?看完这篇你就了解了~
③📖 对于大前端开发来说,转鸿蒙开发究竟是福还是祸?
④📖 鸿蒙岗位需求突增!移动端、PC端、IoT到底该怎么选?
⑤📖 记录一场鸿蒙开发岗位面试经历~
⑥📖 持续更新中……
一、前言
在task_manager部分,主要负责对任务的管理,从消息队列获取消息并处理。在distributedschedule_samgr_lite\samgr\source\task_manager.h中对声明对任务池操作的方法。在distributedschedule_samgr_lite\samgr\source\task_manager.c中对相关方法进行了实现。
二、头文件分析
#ifndef MAX_TASK_SIZE
#define MAX_TASK_SIZE 0xFFFFFF //任务的最大数
#endif
//引用的最大数
#define MAX_REF_NUM 15
//消息处理的最大时间间隔
#define MSG_PROC_THRESHOLD (10 * 1000)
#define GET_REMAIN_TIME(time) ((0xFFFFFFFF - (time)) + 1)
//计算时间间隔
#define GET_INTERVAL(last, now) (((last) > (now)) ? (GET_REMAIN_TIME(last) + (now)) : ((now) - (last)))
typedef struct TaskPool TaskPool;
struct TaskPool {
MQueueId queueId; //消息队列ID
uint16 stackSize; //栈大小,用于配置线程的栈
uint8 priority; //任务的优先级,用于配置线程的优先级
uint8 size; //任务池的大小,维护的线程数
uint8 top; //标识tasks中的线程ID的个数
int8 ref; //引用数
ThreadId tasks[0]; //记录任务池下属的线程ID
};
//创建任务池
TaskPool *SAMGR_CreateFixedTaskPool(const TaskConfig *config, const char *name, uint8 size);
//启动任务池
int32 SAMGR_StartTaskPool(TaskPool *pool, const char *name);
//释放任务池
int32 SAMGR_ReleaseTaskPool(TaskPool *pool);
//引用任务池
TaskPool *SAMGR_ReferenceTaskPool(TaskPool *pool);
//获取当前的消息队列ID
MQueueId SAMGR_GetCurrentQueueID(void);
函数实现分析
任务池的创建
#ifndef MAX_TASK_SIZE
#define MAX_TASK_SIZE 0xFFFFFF //任务的最大数
#endif
//引用的最大数
#define MAX_REF_NUM 15
//消息处理的最大时间间隔
#define MSG_PROC_THRESHOLD (10 * 1000)
#define GET_REMAIN_TIME(time) ((0xFFFFFFFF - (time)) + 1)
//计算时间间隔
#define GET_INTERVAL(last, now) (((last) > (now)) ? (GET_REMAIN_TIME(last) + (now)) : ((now) - (last)))
typedef struct TaskPool TaskPool;
struct TaskPool {
MQueueId queueId; //消息队列ID
uint16 stackSize; //栈大小,用于配置线程的栈
uint8 priority; //任务的优先级,用于配置线程的优先级
uint8 size; //任务池的大小,维护的线程数
uint8 top; //标识tasks中的线程ID的个数
int8 ref; //引用数
ThreadId tasks[0]; //记录任务池下属的线程ID
};
//创建任务池
TaskPool *SAMGR_CreateFixedTaskPool(const TaskConfig *config, const char *name, uint8 size);
//启动任务池
int32 SAMGR_StartTaskPool(TaskPool *pool, const char *name);
//释放任务池
int32 SAMGR_ReleaseTaskPool(TaskPool *pool);
//引用任务池
TaskPool *SAMGR_ReferenceTaskPool(TaskPool *pool);
//获取当前的消息队列ID
MQueueId SAMGR_GetCurrentQueueID(void);
任务池的启动
/*
函数功能:启动任务池
函数参数:@pool:指向任务池的指针
@name:创建的线程名
函数返回:成功 返回EC_SUCCESS,失败 返回EC_INVALID
函数描述:向任务池中添加新创建的线程,创建的线程数等于pool->size值
*/
int32 SAMGR_StartTaskPool(TaskPool *pool, const char *name)
{
//参数检查
if (pool == NULL) {
return EC_INVALID;
}
//任务池中维护的线程数大于0时,返回EC_SUCCESS
if (pool->top > 0) {
return EC_SUCCESS;
}
//后续语句为pool->top小于或等于0才会执行
//配置线程属性
ThreadAttr attr = {name, pool->stackSize, pool->priority, 0, 0};
//创建pool->size个线程
while (pool->top < pool->size) {
/*
创建线程,运行的函数为TaskEntry
@1:创建的线程开始运行的函数地址
@2:运行函数需要的参数
@3:线程属性
*/
register ThreadId threadId = (ThreadId)THREAD_Create(TaskEntry, pool->queueId, &attr);
if (threadId == NULL) {
//记录错误日志
HILOG_ERROR(HILOG_MODULE_SAMGR, "Start Task<%s, %d, %d> failed!", name, pool->stackSize, pool->priority);
break;
}
//记录线程ID
pool->tasks[pool->top] = threadId;
++(pool->top);
}
return EC_SUCCESS;
}
释放任务池的内存
/*
函数功能:释放任务池的内存
函数返回:成功 返回EC_SUCCESS,失败 返回EC_INVALID
函数描述:更新任务池的引用数,若==0则构建消息类型为MSG_EXIT的exchange对象,发送到消息队列中,指示本任务池中的线程退出。并释放任务池。
*/
int32 SAMGR_ReleaseTaskPool(TaskPool *pool)
{
if (pool == NULL) {
return EC_INVALID;
}
//对任务池的引用计数减一
pool->ref--;
if (pool->ref == 0) {
//如果任务池未被其他对象引用,则回收资源
//初始化一个MSG_EXIT类型的exchange对象
Exchange exchange = {0};
//消息类型为MSG_EXIT,当任务池中的线程处理到消息队列中的这条消息时,会停止执行并退出
exchange.type = MSG_EXIT;
//将类型为MSG_EXIT的exchange对象发送到任务池绑定的消息队列中
QUEUE_Put(pool->queueId, &exchange, 0, DONT_WAIT);
//释放资源
SAMGR_Free(pool);
}
return EC_SUCCESS;
}
增加任务池的引用数
//引用对应的任务池,增加任务池的引用计数
TaskPool *SAMGR_ReferenceTaskPool(TaskPool *pool)
{
if (pool == NULL) {
return NULL;
}
if (pool->ref >= MAX_REF_NUM) {
//引用数超出最大值
return NULL;
}
//引用数自增
pool->ref++;
return pool;
}
task_manager剩下的部分实现将在下一篇进行分析。