1. 创建并运行第一个QNX进程

创建并运行第一个QNX进程 学习卡片

任务目标

在QNX Neutrino实时操作系统上,从零创建一个C语言进程:编写源码、使用qcc编译、部署到目标机并运行,观察进程从创建到退出的完整生命周期。

环境准备

  • QNX SDP(Software Development Platform)7.0或7.1,安装在宿主机(Windows/Linux)
  • QNX目标机(或QNX虚拟机),与宿主机网络互通
  • 宿主机与目标机已配置好qconn连接,或可通过SSH/FTP传输文件

完整实现

创建文件first_process.c,代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/procfs.h>
#include <process.h>

int main(int argc, char *argv[]) {
    pid_t pid = getpid();
    pid_t ppid = getppid();

    printf("进程启动: PID=%d, 父进程PPID=%d\n", pid, ppid);
    printf("命令行参数: argc=%d\n", argc);
    for (int i = 0; i < argc; i++) {
        printf("  argv[%d] = %s\n", i, argv[i]);
    }

    // 获取进程名称(来自 /proc/self 的进程信息)
    char name[64] = {0};
    procfs_processinfo_t info;
    DIR *dir = opendir("/proc/self");
    if (dir) {
        // 简化方式:直接读取进程名
        FILE *f = fopen("/proc/self/name", "r");
        if (f) {
            fgets(name, sizeof(name), f);
            fclose(f);
        }
        closedir(dir);
    }
    printf("进程名称: %s", name[0] ? name : "(读取失败)\n");

    printf("进程进入运行状态,休眠2秒模拟工作...\n");
    sleep(2);

    printf("进程准备退出,返回码=0\n");
    return 0;
}

编译与部署

在宿主机QNX SDP的Bash环境中执行以下命令:

# 编译(生成x86_64目标文件)
qcc -Vgcc_ntox86_64 -o first_process first_process.c

# 查看生成的文件类型
file first_process

# 传输到目标机(假设目标机IP为192.168.1.100)
scp first_process qnxuser@192.168.1.100:/tmp/

若目标机为ARM架构(如i.MX8),将gcc_ntox86_64替换为对应的gcc_ntoarmv7le或gcc_ntoaarch64le。

运行与验证

在目标机终端执行:

# 添加执行权限并运行
chmod +x /tmp/first_process
/tmp/first_process arg1 arg2

预期输出(与代码逻辑严格对应):

进程启动: PID=4105, 父进程PPID=1
命令行参数: argc=3
  argv[0] = /tmp/first_process
  argv[1] = arg1
  argv[2] = arg2
进程名称: first_process
进程进入运行状态,休眠2秒模拟工作...
进程准备退出,返回码=0

验证通过条件:

  1. 程序输出完整的生命周期信息:启动(含PID/PPID)→ 参数解析 → 运行中 → 退出
  2. 在程序休眠的2秒内,在目标机另开终端执行pidin | grep first_process,能看到该进程处于RUN状态
  3. 程序退出后再次执行pidin | grep first_process,无输出,证明进程已终止
  4. 执行echo $?显示返回码为0

进程生命周期说明

QNX进程生命周期包含四个阶段:创建(由fork/exec或spawn触发)、就绪/运行(调度器分配CPU)、阻塞/等待(如sleep)、退出(调用exit或return)。本案例通过getpid()获取内核分配的PID,通过sleep()制造阻塞状态,通过return 0触发正常退出,完整覆盖了进程从生到死的路径。

若需观察进程退出时的状态码,可在目标机执行waitpid工具或使用tracelogger跟踪系统调用,但本案例通过$?已能确认退出码。