3、进程与线程基础:进程的概念与生命周期、线程的概念与调度、进程与线程的区别

好,咱们今天聊聊进程和线程。这是操作系统的核心概念,也是很多嵌入式开发者容易混淆的地方。我记得刚接触QNX那会儿,也在这上面栽过跟头。别急,咱们一个一个掰开揉碎了讲。

3.1 进程的概念与生命周期

进程是什么?说白了,就是一个正在运行的程序实例。你写了一段C代码,编译成可执行文件,放在硬盘上,那叫程序。当你双击运行它,或者用命令行启动它,系统为它分配了内存、打开了文件、创建了各种资源——这时候,它就变成了一个进程。

在QNX里,进程是资源分配的最小单位。每个进程都有自己的地址空间,互不干扰。我做过一个车载仪表盘的项目,仪表盘进程和导航进程就是两个独立的进程。一个崩了,另一个还能正常工作。这就是进程隔离的好处。

进程的四个关键要素:

  • PID:进程ID,系统里唯一的标识符
  • 地址空间:代码、数据、堆、栈,都在自己的地盘里
  • 资源句柄:打开的文件、信号量、消息队列等
  • 执行上下文:寄存器状态、程序计数器等

进程的生命周期,其实就五个状态:

状态 说明 我踩过的坑
创建(New) 调用fork()或spawn(),系统分配资源 曾经忘记检查fork返回值,子进程没创建成功,程序直接跑飞了
就绪(Ready) 万事俱备,只等CPU
运行(Running) CPU正在执行它的指令
阻塞(Blocked) 等某个事件,比如等I/O完成 调试一个串口驱动时,进程莫名其妙卡住,查了半天发现是读操作阻塞了,没设超时
终止(Terminated) 执行完毕或被kill,释放资源

你想想看,一个进程从创建到终止,中间可能在这几个状态之间来回切换。QNX的调度器会负责这件事,它决定哪个就绪进程能拿到CPU。

小提示:在QNX里,用 pidin 命令可以查看当前所有进程的状态。我调试时几乎离不开这个命令。

3.2 线程的概念与调度

线程又是什么?线程是进程里的一个执行流。一个进程可以有一个或多个线程,它们共享进程的地址空间和资源。

我个人习惯把进程比作一个工厂,线程就是工厂里的工人。工厂(进程)有厂房、设备、原材料(地址空间和资源),工人们(线程)在里面干活,共享这些东西。但每个工人有自己的工具包(栈和寄存器)。

在QNX里,线程是调度和执行的最小单位。调度器不关心进程,它只关心线程。嗯,这里要注意:QNX的调度策略非常灵活,支持以下几种:

  • FIFO调度:先来先服务,直到线程主动放弃CPU或被更高优先级抢占
  • 轮转调度(Round Robin):每个线程分一个时间片,时间到了就换下一个
  • 零星调度(Sporadic):适合偶发性的实时任务,平时低优先级,有事件时提优先级
  • 自适应分区调度(Adaptive Partitioning):QNX的独门绝技,给每个分区分配CPU预算,防止某个分区饿死其他分区

我曾经在一个多路视频处理的项目里,用了自适应分区调度。一个分区跑视频解码,一个分区跑UI,一个分区跑网络通信。结果视频解码分区出了bug,疯狂吃CPU,但其他分区因为有预算保护,照样流畅运行。要是没有这个机制,整个系统早就卡死了。

线程的优先级:QNX支持0-255级优先级,0最高,255最低。实时线程一般用0-63,普通线程用64-255。我建议实时任务优先级别设太高,留点余量给系统关键服务。

3.3 进程与线程的区别

好,到了最关键的部分。进程和线程到底有什么区别?我直接给你列个表,一目了然:

对比项 进程 线程
资源分配单位 是,每个进程独立拥有地址空间 否,共享所属进程的资源
调度单位 不是,调度器调度的是线程 是,线程是调度的基本单位
地址空间 独立,互不干扰 共享,一个线程崩了可能带崩整个进程
创建开销 大,需要分配独立地址空间、页表等 小,只需分配栈和线程控制块
上下文切换 慢,涉及地址空间切换(TLB刷新) 快,不涉及地址空间切换
通信方式 IPC(消息传递、共享内存、信号等) 直接读写共享变量(需加锁)
安全性 高,一个进程崩溃不影响其他进程 低,一个线程出问题可能影响整个进程

说白了,进程是 heavyweight(重量级),线程是 lightweight(轻量级)。

那什么时候用进程,什么时候用线程?我个人的经验是:

  • 需要强隔离、高可靠性:用进程。比如车载系统的仪表盘和娱乐系统,绝对不能互相影响。
  • 需要高性能、低延迟:用线程。比如同一个任务的不同处理阶段,用线程共享数据,省去IPC的开销。
  • 混合使用:这是最常见的。一个进程里开多个线程,同时多个进程之间通过IPC协作。

避坑指南:我曾经在一个项目中,为了省事,把所有功能都塞到一个进程的多个线程里。结果一个线程的野指针把另一个线程的数据给踩了,查了整整两天才定位到问题。从那以后,关键模块我一定拆成独立进程。

最后说一句,QNX的进程和线程模型非常成熟。你只要理解了「进程管资源,线程管执行」这个核心思想,后面学消息传递、同步互斥就会轻松很多。

好,这一章就到这儿。下一章咱们聊聊QNX的进程间通信——消息传递,这可是QNX的看家本领。