4. 进程与线程管理:pidin命令详解、进程状态查看、线程优先级与调度策略

说到QNX的进程线程管理,pidin这个命令,我几乎每天都要用上几十次。它就像系统的听诊器,哪里不对劲,一查便知。今天咱们就把它彻底聊透。

4.1 pidin命令:不只是“看进程”那么简单

很多人以为pidin就是ps的QNX版,其实远不止如此。它能看到的东西,比你想象中多得多。

基础用法,直接敲pidin,你会看到类似这样的输出:

pid tid prio STATE       BLOCKED     NAME
1   1   10   READY                    procnto
2   1   10   RECEIVE     MsgReceive  io-pkt
3   1   10   RECEIVE     MsgReceive  devc-ser8250
4   1   10   RECEIVE     MsgReceive  pipe
5   1   10   RECEIVE     MsgReceive  random
6   1   10   RECEIVE     MsgReceive  devc-con

每一列都有讲究。pid是进程ID,tid是线程ID,prio是优先级,STATE是当前状态,BLOCKED是阻塞原因,NAME是进程名。

我的小习惯: 我一般会先看STATE列。如果发现大量进程处于READY状态,说明CPU可能已经忙不过来了。如果全是RECEIVE或SEND,那系统其实很空闲,都在等消息呢。

4.2 进程状态:读懂每个进程的“心情”

QNX的进程状态,我把它比作人的几种状态——

状态 含义 像什么
READY 就绪,等待CPU调度 排队等公交车
RUNNING 正在运行 正在开车
RECEIVE 阻塞在接收消息 等快递
SEND 阻塞在发送消息 敲门等人开门
REPLY 阻塞在等待回复 发完消息等回信
WAITCTX 等待上下文 等红绿灯
WAITPAGE 缺页中断 翻书找内容
STOPPED 被暂停 被叫停
DEAD 已死亡 凉了

我曾经遇到过一个诡异的问题:系统偶尔卡顿,但CPU占用率并不高。用pidin一看,发现有个进程频繁在WAITPAGE和READY之间切换。说白了,就是内存不够,频繁换页。加根内存条,问题就解决了。

4.3 线程优先级:谁先跑,谁后跑

QNX的优先级范围是0到255,数字越大优先级越高。0是空闲线程,255是最高优先级的中断服务线程。

查看线程优先级,用pidin -p 进程名

# pidin -p my_app
pid tid prio STATE       BLOCKED     NAME
12345 1   50   RECEIVE     MsgReceive  my_app
12345 2   45   READY                    my_app
12345 3   30   RECEIVE     MsgReceive  my_app

你看,同一个进程的不同线程,优先级可以不一样。这很常见——处理紧急数据的线程给高优先级,后台维护的线程给低优先级。

注意: 优先级不是越高越好。我曾经见过一个项目,把所有线程都设成255,结果系统直接崩溃。为什么?高优先级线程霸占CPU,低优先级的系统服务(比如网络、文件系统)根本跑不起来。这叫“优先级反转”的极端情况。

4.4 调度策略:FIFO、RR还是SPORADIC?

QNX支持三种调度策略,我一个个说。

FIFO(先进先出):同优先级的线程,谁先就绪谁先跑,跑完才让下一个跑。适合计算密集型的任务,比如视频编码。

RR(轮转):同优先级的线程,每个跑一个时间片(默认4毫秒),然后换下一个。适合需要公平调度的场景,比如多个用户交互。

SPORADIC(零星调度):这是QNX的特色。给线程一个“预算”,预算用完了就降级到低优先级运行。适合偶发性的高优先级任务,比如按键响应。

查看线程的调度策略,用pidin -m

# pidin -m
pid tid prio policy    NAME
1   1   10   FIFO      procnto
2   1   10   RR        io-pkt
3   1   10   FIFO      devc-ser8250

我个人的经验是:中断处理线程用FIFO,普通应用线程用RR,不确定的用SPORADIC。SPORADIC是个好东西,但很多人不会用,可惜了。

4.5 实战:用pidin定位性能瓶颈

光说不练假把式。咱们来一个真实场景。

假设系统反应迟钝,你怀疑是某个线程占用了太多CPU。怎么做?

第一步,看整体:

pidin -p all -F "%p %c %a"

这个命令会显示每个进程的CPU占用率。找到占用最高的那个进程。

第二步,看线程:

pidin -p 高占用进程ID -t -F "%t %p %c %a"

找到具体是哪个线程在吃CPU。

第三步,看调度:

pidin -p 高占用进程ID -m

看看这个线程的优先级和调度策略是否合理。

避坑指南: 我曾经遇到一个案例,一个线程的优先级设成了200,但它其实只是个日志记录线程。结果每次它一跑,其他所有线程都得等着。把优先级降到50,系统瞬间流畅了。所以,优先级不是越高越好,够用就行

4.6 动态调整:不用重启也能改

QNX允许你在运行时调整线程的优先级和调度策略。用pidin配合sched_setscheduler或者chrt命令。

比如,把线程12345的优先级从50改成80:

chrt -p 80 12345

或者用C代码:

#include <sys/sched.h>
struct sched_param param;
param.sched_priority = 80;
sched_setscheduler(0, SCHED_RR, &param);

嗯,这里要注意:改优先级要谨慎。你想想看,如果把一个普通线程的优先级改得比系统服务还高,那系统服务可能就得不到及时响应了。

4.7 总结一下

pidin这个工具,说简单也简单,说复杂也复杂。关键是你要知道看什么、怎么看。

  • 看状态:READY多说明CPU忙,RECEIVE多说明系统闲
  • 看优先级:255是最高,0是最低,别乱设
  • 看调度策略:FIFO适合中断,RR适合普通任务,SPORADIC适合偶发任务
  • 动态调整:用chrt或sched_setscheduler,但别手滑

我个人习惯是,每次调试新系统,第一件事就是跑一遍pidin -p all -F "%p %c %a",看看各个进程的CPU占用。这就像医生看病先量体温一样,基础但有效。

好了,这一章就到这里。下一章咱们聊聊内存管理,那又是一个大坑。