4. 任务删除与自我保护
任务概述
本案例演示VxWorks中任务删除的两种方式:主动删除(任务自身调用taskDelete)与被动删除(其他任务调用taskDelete),并重点处理任务被删除时的资源清理问题。核心难点在于:任务可能持有动态分配的内存、信号量或文件描述符,若直接删除而不清理,将导致资源泄漏。本案例通过注册删除钩子函数(taskDeleteHookAdd)实现资源自动回收。
实现方案
创建两个任务:workerTask动态分配内存并持有互斥信号量,模拟占用资源后主动退出;deleteTask负责删除一个长时间运行的任务,演示被动删除场景。两个任务均注册删除钩子,在任务被删除时自动释放内存与信号量。主函数创建任务后延时等待,通过shell命令观察任务状态与资源释放情况。
关键完整代码
/* taskDeleteDemo.c - 任务删除与自我保护示例 */
#include <vxWorks.h>
#include <taskLib.h>
#include <semLib.h>
#include <stdlib.h>
#include <stdio.h>
/* 任务状态结构 */
typedef struct {
char *buffer; /* 动态分配的内存 */
SEM_ID semaphore; /* 持有的信号量 */
int taskId; /* 任务ID */
} TaskResource;
/* 删除钩子函数:任务被删除时自动调用 */
void resourceCleanupHook(TaskResource *res)
{
if (res == NULL)
return;
if (res->buffer != NULL) {
free(res->buffer);
res->buffer = NULL;
printf("Hook: buffer freed for task %d\n", res->taskId);
}
if (res->semaphore != NULL) {
semDelete(res->semaphore);
res->semaphore = NULL;
printf("Hook: semaphore deleted for task %d\n", res->taskId);
}
}
/* 主动删除任务:分配资源后自行退出 */
void workerTask(void)
{
TaskResource res;
res.buffer = (char *)malloc(1024);
res.semaphore = semMCreate(SEM_Q_PRIORITY);
res.taskId = taskIdSelf();
if (res.buffer == NULL || res.semaphore == NULL) {
printf("Worker: resource allocation failed\n");
if (res.buffer) free(res.buffer);
if (res.semaphore) semDelete(res.semaphore);
return;
}
/* 注册删除钩子 */
taskDeleteHookAdd(resourceCleanupHook, &res);
printf("Worker task %d started, resources allocated\n", res.taskId);
taskDelay(sysClkRateGet() * 2); /* 运行2秒 */
/* 主动删除自己,触发钩子清理 */
printf("Worker: deleting itself\n");
taskDelete(taskIdSelf());
}
/* 被动删除任务:长时间运行,等待被其他任务删除 */
void longRunningTask(void)
{
TaskResource res;
res.buffer = (char *)malloc(2048);
res.semaphore = semMCreate(SEM_Q_PRIORITY);
res.taskId = taskIdSelf();
if (res.buffer == NULL || res.semaphore == NULL) {
printf("LongTask: resource allocation failed\n");
if (res.buffer) free(res.buffer);
if (res.semaphore) semDelete(res.semaphore);
return;
}
taskDeleteHookAdd(resourceCleanupHook, &res);
printf("Long task %d started, will run forever\n", res.taskId);
while (1) {
taskDelay(sysClkRateGet()); /* 每秒打印一次 */
printf("Long task %d still running...\n", res.taskId);
}
}
/* 删除发起任务 */
void deleteTask(void)
{
int longTaskId;
taskDelay(sysClkRateGet() * 3); /* 等待3秒后执行删除 */
/* 查找长任务ID(通过任务名) */
longTaskId = taskNameToId("tLongTask");
if (longTaskId == ERROR) {
printf("DeleteTask: cannot find tLongTask\n");
return;
}
printf("DeleteTask: deleting tLongTask (ID=%d)\n", longTaskId);
taskDelete(longTaskId);
printf("DeleteTask: tLongTask deleted\n");
}
/* 主入口:创建三个任务 */
void taskDeleteDemo(void)
{
taskSpawn("tWorker", 100, 0, 20000, (FUNCPTR)workerTask, 0,0,0,0,0,0,0,0,0,0);
taskSpawn("tLongTask", 100, 0, 20000, (FUNCPTR)longRunningTask, 0,0,0,0,0,0,0,0,0,0);
taskSpawn("tDelete", 150, 0, 20000, (FUNCPTR)deleteTask, 0,0,0,0,0,0,0,0,0,0);
}
运行与验证
编译与加载:在VxWorks开发环境中编译上述代码生成taskDeleteDemo.o,通过FTP或WindSh加载到目标机。
执行入口:在Shell中调用taskDeleteDemo()启动演示。
预期输出与判定标准:
- 启动后约2秒内,应看到
Worker task [ID] started和Long task [ID] started,表明两个任务成功分配资源并运行。 - 约2秒后,
Worker: deleting itself出现,随后紧跟Hook: buffer freed和Hook: semaphore deleted,证明主动删除时钩子被调用、资源已释放。 - 约3秒后,
DeleteTask: deleting tLongTask出现,随后同样出现两条Hook释放信息,证明被动删除时钩子同样生效。 - 在Shell执行
taskShow,确认tWorker、tLongTask、tDelete三个任务均已不存在,且系统无内存泄漏(可用memShow对比前后空闲内存)。
注意事项:删除钩子函数运行在删除者的上下文中,因此钩子内不能调用可能阻塞的操作(如semTake)。若任务持有VxWorks信号量且被删除时未释放,系统不会自动回收,必须通过钩子显式处理。本示例中taskDeleteHookAdd注册的钩子在任务被删除时自动执行,无需手动调用清理函数。