2. QNX进程管理基础
任务目标
在QNX Neutrino实时操作系统上,编写一个C程序演示多进程生命周期管理:使用fork()创建子进程,通过exec()族函数加载新程序,利用waitpid()回收子进程并检查其退出状态。程序需输出每个阶段的进程PID与状态变化,便于在QNX Shell中直接观察验证。
环境与依赖
- QNX SDP 7.0或更高版本(含
qcc编译器) - 目标机为x86_64或ARM架构的QNX Neutrino运行时
- 无需额外库,仅依赖POSIX标准头文件
核心实现
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>
#include <sys/types.h>
#include <errno.h>
#define CHILD_COUNT 3
int main(void) {
pid_t pids[CHILD_COUNT];
int i;
printf("父进程 PID=%d 开始\n", getpid());
// 创建3个子进程
for (i = 0; i < CHILD_COUNT; i++) {
pid_t pid = fork();
if (pid < 0) {
perror("fork失败");
exit(EXIT_FAILURE);
}
if (pid == 0) {
// 子进程分支:执行外部命令
char arg[8];
snprintf(arg, sizeof(arg), "%d", i + 1);
printf("子进程 PID=%d (来自fork #%d) 准备exec\n", getpid(), i + 1);
execl("/bin/echo", "echo", "子进程", arg, "执行完毕", (char *)NULL);
// 仅当exec失败时才会到达此处
perror("exec失败");
_exit(EXIT_FAILURE);
}
pids[i] = pid;
}
// 父进程回收所有子进程
for (i = 0; i < CHILD_COUNT; i++) {
int status;
pid_t ret = waitpid(pids[i], &status, 0);
if (ret == -1) {
perror("waitpid失败");
continue;
}
if (WIFEXITED(status)) {
printf("回收子进程 PID=%d,退出码=%d\n", ret, WEXITSTATUS(status));
} else if (WIFSIGNALED(status)) {
printf("回收子进程 PID=%d,被信号 %d 终止\n", ret, WTERMSIG(status));
}
}
printf("父进程 PID=%d 结束\n", getpid());
return EXIT_SUCCESS;
}
编译与运行
# 在QNX主机开发环境编译
qcc -o proc_mgmt proc_mgmt.c
# 将可执行文件复制到目标机(或直接在目标机编译)
# 在目标机QNX Shell中运行
./proc_mgmt
验证方法与判定标准
运行程序后,观察输出应满足以下条件即判定通过:
- 父进程先打印启动信息,随后依次创建3个子进程。
- 每个子进程在
exec前打印自己的PID,exec后由/bin/echo输出对应文本(证明exec成功替换了进程映像)。 - 父进程最终按创建顺序回收全部子进程,并打印每个子进程的PID与退出码0。
- 程序正常退出,无
fork失败或exec失败错误信息。
若需观察进程状态变化,可在程序运行期间于另一个Shell执行pidin | grep proc_mgmt,可看到父进程与子进程的瞬时状态(如RUN/WAIT),但注意子进程生命周期极短,需快速执行或适当增加延时才能捕获。
关键说明
fork()返回两次:父进程收到子进程PID,子进程收到0;返回-1表示失败。- 子进程必须使用
_exit()而非exit(),避免刷新父进程的stdio缓冲区造成重复输出。 exec成功后原进程代码不再执行,因此perror("exec失败")仅在exec返回-1时触发。- 父进程使用
waitpid精确等待指定子进程,避免回收顺序混乱。