【数据结构】【task_group】

本文详细解析了Linux内核中的task_group结构,探讨了其在CFS和实时调度器中的作用,以及如何通过task_group实现进程组的管理和调度。文章涵盖了进程组在各CPU上的调度实体和运行队列,以及与之相关的负载平均、优先级和带宽管理。

task_group

/* task group related information */
struct task_group {
	/* 用于进程找到其所属进程组结构 */
	struct cgroup_subsys_state css;

#ifdef CONFIG_FAIR_GROUP_SCHED
	/* schedulable entities of this group on each cpu */
	/* CFS调度器的进程组变量,在 alloc_fair_sched_group() 中进程初始化及分配内存 */
/* 该进程组在每个CPU上都有对应的一个调度实体,因为有可能此进程组同时在两个CPU上
 运行(它的A进程在CPU0上运行,B进程在CPU1上运行) */

	struct sched_entity **se;
	/* runqueue "owned" by this group on each cpu */
	/* 进程组在每个CPU上都有一个CFS运行队列(为什么需要,稍后解释) */
	struct cfs_rq **cfs_rq;
	/* 用于保存优先级默认为NICE 0的优先级 ,这个数值是常量*/
	unsigned long shares;

#ifdef	CONFIG_SMP
	/*
	 * load_avg can be heavily contended at clock tick time, so put
	 * it in its own cacheline separated from the fields above which
	 * will also be accessed at each tick.
	 */
	atomic_long_t load_avg ____cacheline_aligned;
#endif
#endif

#ifdef CONFIG_RT_GROUP_SCHED
/* 实时进程调度器的进程组变量,同 CFS */
	struct sched_rt_entity **rt_se;
	struct rt_rq **rt_rq;

	struct rt_bandwidth rt_bandwidth;
#endif

	struct rcu_head rcu;
	/* 用于建立进程链表(属于此调度组的进程链表) */
	struct list_head list;
/* 指向其上层的进程组,每一层的进程组都是它上一层进程组的运行队列的一个调度实体
,在同一层中,进程组和进程被同等对待 */
	struct task_group *parent;
	/* 进程组的兄弟结点链表 */
	struct list_head siblings;
	/* 进程组的儿子结点链表 */
	struct list_head children;

#ifdef CONFIG_SCHED_AUTOGROUP
	struct autogroup *autogroup;
#endif

	struct cfs_bandwidth cfs_bandwidth;
};

 

你提供的代码是一个 **基于宏定义的调度任务表初始化**,用于嵌入式系统中配置周期性执行的任务(如实时操作系统或裸机轮询架构中的任务调度器)。我们来详细分析其结构、作用、潜在问题,并提供优化建议。 --- ### ✅ 代码功能解析 ```c #if (BMS_COMM_PROTOCOL_TYPE == 01) #define SCHE_TASK_DEFAULT { \ {&DEBUG_DrvTask, SCHE_DEBUG_TASK_GROUP, SCHE_DEDBUG_TASK_MS, 0, NULL}, \ {&WDT_RefreshWatchDog, SCHE_WDT_TASK_GROUP, SCHE_WDT_TASK_MS, 0, NULL}, \ {&PANEL_SrvTask, SCHE_PANEL_TASK_GROUP, SCHE_PANEL_TASK_MS}, \ {&PARAM_Task, SCHE_PARAM_TASK_GROUP, SCHE_PARAM_TASK_MS}, \ {&PWR_Task, SCHE_PWR_TASK_GROUP, SCHE_PWR_TASK_MS}, \ {&FAIL_DrvTask, SCHE_FAILURE_DRV_TASK_GROUP, SCHE_FAILURE_DRV_TASK_MS}, \ {&FLASH_SrvTask, SCHE_FLASH_SRV_TASK_GROUP, SCHE_FLASH_SRV_TASK_MS}, \ {&FLASH_DrvTimeoutTask, SCHE_FLASH_DRV_TIMEOUT_TASK_GROUP, SCHE_FLASH_DRV_TIMEOUT_TASK_MS}, \ {&FAIL_SrvTask, SCHE_FAILURE_SRV_TASK_GROUP, SCHE_FAILURE_SRV_TASK_MS}, \ {&HIS_SrvTask, SCHE_HISTORY_SRV_TASK_GROUP, SCHE_HISTORY_SRV_TASK_MS}, \ {&CAN_AppCycleHandle, SCHE_CAN_TASK_GROUP, SCHE_CAN_TASK_MS}, \ {&SD3010_SrvTask, SCHE_SD3010_TASK_GROUP, SCHE_SD3010_TASK_MS}, \ {&TM_AppTask, SCHE_TM_TASK_GROUP, SCHE_TM_TASK_MS} \ } #endif ``` --- ## 🧱 结构说明 这是一个 **数组初始化列表**,用于初始化一个任务调度表。每个元素代表一个可调度任务,格式为: ```c {函数指针, 组ID, 周期(毫秒), 上次运行时间, 状态数据} ``` 推测结构体定义如下(常见于嵌入式调度器): ```c typedef struct { void (*task_func)(void); // 任务函数指针 uint8_t group_id; // 调度分组(优先级或分类) uint16_t period_ms; // 执行周期(单位:ms) uint32_t last_run_time; // 上次执行的时间戳(自动更新) void *state; // 私有状态(如上下文) } ScheTask_t; ``` > 注:最后两个字段在部分条目中省略,默认初始化为 `0` 和 `NULL` --- ## 🔍 各任务简要说明 | 任务函数 | 功能 | |--------|------| | `DEBUG_DrvTask` | 调试信息输出 | | `WDT_RefreshWatchDog` | 看门狗喂狗,防止复位 | | `PANEL_SrvTask` | 面板控制服务 | | `PARAM_Task` | 参数管理(读写EEPROM/Flash等) | | `PWR_Task` | 电源管理任务 | | `FAIL_DrvTask` | 故障检测底层驱动 | | `FLASH_SrvTask` | Flash 操作服务 | | `FLASH_DrvTimeoutTask` | Flash 驱动超时处理 | | `FAIL_SrvTask` | 故障处理上层逻辑 | | `HIS_SrvTask` | 历史数据记录服务 | | `CAN_AppCycleHandle` | CAN通信周期处理 | | `SD3010_SrvTask` | 特定芯片(如计量IC)服务任务 | | `TM_AppTask` | 定时管理或时间同步任务 | --- ## ⚠️ 存在的问题与改进建议 ### ❌ 1. **拼写错误:`SCHE_DEDBUG_TASK_MS` 应为 `SCHE_DEBUG_TASK_MS`** ```c {&DEBUG_DrvTask, SCHE_DEBUG_TASK_GROUP, SCHE_DEDBUG_TASK_MS, 0, NULL} // ^^^^^^^^^^^^^^^^ 错误拼写! ``` ✅ 正确应为: ```c SCHE_DEBUG_TASK_MS ``` 否则编译时报错:“undefined identifier” 👉 **必须修复!** --- ### ❌ 2. **部分任务缺少最后两个字段,依赖默认初始化** 例如: ```c {&PANEL_SrvTask, SCHE_PANEL_TASK_GROUP, SCHE_PANEL_TASK_MS} ``` → 缺少 `last_run_time` 和 `state` 字段 虽然 C 标准允许 **聚合初始化补零**(trailing elements are zero-initialized),但为了清晰和可维护性,建议显式写出: ```c {&PANEL_SrvTask, SCHE_PANEL_TASK_GROUP, SCHE_PANEL_TASK_MS, 0, NULL} ``` 📌 尤其当结构体将来可能扩展时,隐式初始化容易出错。 --- ### ❌ 3. **宏名使用八进制?`01` 是八进制表示法!** ```c #if (BMS_COMM_PROTOCOL_TYPE == 01) ``` ⚠️ 这里 `01` 是合法的 **八进制整数**(等于十进制 1),但写成 `01` 极易误导他人以为是 `1` 的笔误。 ✅ 更清晰写法: ```c #if (BMS_COMM_PROTOCOL_TYPE == 1) ``` 或者使用宏定义避免魔法数字: ```c #define BMS_PROTOCOL_MODBUS 1 #if (BMS_COMM_PROTOCOL_TYPE == BMS_PROTOCOL_MODBUS) ``` --- ### ✅ 推荐改进版本(修正后) ```c #if (BMS_COMM_PROTOCOL_TYPE == 1) // 修复八进制写法,更清晰 #define SCHE_TASK_DEFAULT { \ {&DEBUG_DrvTask, SCHE_DEBUG_TASK_GROUP, SCHE_DEBUG_TASK_MS, 0, NULL}, \ {&WDT_RefreshWatchDog, SCHE_WDT_TASK_GROUP, SCHE_WDT_TASK_MS, 0, NULL}, \ {&PANEL_SrvTask, SCHE_PANEL_TASK_GROUP, SCHE_PANEL_TASK_MS, 0, NULL}, \ {&PARAM_Task, SCHE_PARAM_TASK_GROUP, SCHE_PARAM_TASK_MS, 0, NULL}, \ {&PWR_Task, SCHE_PWR_TASK_GROUP, SCHE_PWR_TASK_MS, 0, NULL}, \ {&FAIL_DrvTask, SCHE_FAILURE_DRV_TASK_GROUP, SCHE_FAILURE_DRV_TASK_MS, 0, NULL}, \ {&FLASH_SrvTask, SCHE_FLASH_SRV_TASK_GROUP, SCHE_FLASH_SRV_TASK_MS, 0, NULL}, \ {&FLASH_DrvTimeoutTask, SCHE_FLASH_DRV_TIMEOUT_TASK_GROUP, SCHE_FLASH_DRV_TIMEOUT_TASK_MS, 0, NULL}, \ {&FAIL_SrvTask, SCHE_FAILURE_SRV_TASK_GROUP, SCHE_FAILURE_SRV_TASK_MS, 0, NULL}, \ {&HIS_SrvTask, SCHE_HISTORY_SRV_TASK_GROUP, SCHE_HISTORY_SRV_TASK_MS, 0, NULL}, \ {&CAN_AppCycleHandle, SCHE_CAN_TASK_GROUP, SCHE_CAN_TASK_MS, 0, NULL}, \ {&SD3010_SrvTask, SCHE_SD3010_TASK_GROUP, SCHE_SD3010_TASK_MS, 0, NULL}, \ {&TM_AppTask, SCHE_TM_TASK_GROUP, SCHE_TM_TASK_MS, 0, NULL} \ } #endif ``` --- ## ✅ 使用方式示例(如何使用这个宏) 通常用它来初始化一个全局任务数组: ```c ScheTask_t g_sche_tasks[] = SCHE_TASK_DEFAULT; uint8_t g_sche_task_count = sizeof(g_sche_tasks) / sizeof(g_sche_tasks[0]); ``` 然后在主循环中由调度器遍历执行: ```c for (int i = 0; i < g_sche_task_count; i++) { uint32_t now = GetSysTickMs(); if ((now - g_sche_tasks[i].last_run_time) >= g_sche_tasks[i].period_ms) { g_sche_tasks[i].task_func(); g_sche_tasks[i].last_run_time = now; } } ``` ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值