任务基础:任务控制块(TCB)、任务状态与状态转换、任务创建与删除
好,咱们正式开始聊任务。很多初学者觉得任务不就是个函数吗?嗯,这么说也对,但不够准确。在VxWorks里,任务是一个有“身份”的实体。这个身份,就记录在任务控制块(TCB)里。
1. 任务控制块(TCB)——任务的“身份证”
每个任务被创建时,内核都会给它分配一个TCB。你可以把TCB想象成一张档案卡,上面写着这个任务的所有关键信息。
TCB里到底存了什么?
- 任务ID(TID):唯一标识,就像你的身份证号。我调试时经常用
taskIdSelf()来获取当前任务的ID。 - 优先级:决定了谁先抢到CPU。这个后面会细讲。
- 栈指针和栈大小:每个任务都有自己的栈。栈给太小,任务容易崩;给太大,浪费内存。我曾经在一个项目中,因为栈只给了1024字节,结果任务一跑复杂逻辑就挂,查了两天才发现是栈溢出。
- 程序计数器(PC):记录任务执行到哪一行代码了。
- 任务状态:就绪、阻塞、挂起……下面会讲。
- 错误状态:任务出错了,这里会记录错误码。
核心观点:TCB是内核管理任务的根本。你写的每个任务,内核都是通过TCB来感知它的存在。说白了,没有TCB,任务就是个孤魂野鬼。
2. 任务状态与状态转换——任务的一生
任务不是一直在跑的。它会在几个状态之间跳来跳去。理解这个,对后面做优先级设计特别重要。
VxWorks里主要有这几个状态:
| 状态 | 含义 | 我常遇到的情况 |
|---|---|---|
| READY | 就绪态。任务啥都准备好了,就等CPU。 | 高优先级任务一就绪,低优先级的就得让路。 |
| PEND | 阻塞态。任务在等某个资源(比如信号量、消息队列)。 | 我曾经调试一个死锁问题,发现两个任务都在PEND状态,谁也不让谁。 |
| SUSPEND | 挂起态。任务被强制暂停,不参与调度。 | 调试时我常用 taskSuspend 临时停掉一个任务,看看系统反应。 |
| DELAY | 延时态。任务调用 taskDelay() 后进入。 |
说白了就是任务主动说:“我先睡一会儿,到点叫我。” |
| RUNNING | 运行态。任务正在使用CPU。 | 单核CPU下,同一时刻只有一个任务在RUNNING状态。 |
状态是怎么转换的?
举个例子:你创建了一个任务,它先进入READY态。调度器一看,嗯,你优先级最高,让你跑。它就变成RUNNING。跑着跑着,它要等一个信号量,但信号量被别人占着,它就乖乖进入PEND态。等信号量释放了,它又回到READY态,等着再次被调度。
我的小技巧:调试时用 i 命令(或 taskShow)查看所有任务的状态。如果发现某个任务长期卡在PEND,十有八九是资源没释放。我曾经靠这招抓出过好几个隐藏的bug。
3. 任务创建与删除——taskSpawn / taskDelete
创建任务,最常用的就是 taskSpawn。删除任务,用 taskDelete。这两个函数,你写VxWorks程序几乎天天见。
taskSpawn 长什么样?
int taskSpawn(
char *name, // 任务名,调试时很有用
int priority, // 优先级,0-255,0最高
int options, // 选项,比如 VX_FP_TASK(浮点运算)
int stackSize, // 栈大小,单位字节
FUNCPTR entryPt, // 任务入口函数
int arg1, // 参数1
int arg2, // 参数2
...
);
创建任务时,我踩过的坑:
- 栈大小给太小:任务一运行就崩。我建议至少给4096字节起步,复杂任务给8192以上。
- 优先级给太高:系统任务(比如tExcTask)优先级是0,你把自己的任务也设成0,可能会把系统搞死。我个人习惯,应用任务优先级设在50-200之间。
- options没设对:如果任务里用浮点运算,一定要加
VX_FP_TASK,否则结果全乱套。
taskDelete 怎么用?
STATUS taskDelete(int tid); // 删除指定ID的任务
删除任务时,千万注意:
警告:不要随便删除一个正在使用共享资源的任务!比如它正拿着一个互斥信号量,你把它删了,信号量就永远没人释放了。其他等这个信号量的任务会永久阻塞。这就是典型的死锁隐患。
我曾经在一个项目中,为了快速清理异常任务,直接调了 taskDelete。结果系统跑着跑着就卡死了。查了半天,发现被删的任务正占着一个内存池的锁。从那以后,我删除任务前都会先确保它已经释放了所有资源。
避坑指南:如果你不确定任务是否安全,可以用 taskSafe 和 taskUnsafe 来保护关键区域。但说实话,最好的办法是让任务自己退出(比如在入口函数里return),而不是外部强制删除。
好了,任务的基础就这些。你想想看,TCB是任务的身份证,状态是任务的当前处境,创建和删除是任务的生与死。把这些搞明白了,后面讲优先级和死锁,你才能听得更透。