进程的基本概念\相关命令\创建\调度\状态及相关函数接口---软件编程---嵌入式(Linux)

1、进程和线程

1.1 进程基本概念

  • 程序: 存放在硬盘中的静态指令和数据集合,无执行状态。
  • 进程: 是程序的动态执行实例(动态执行的过程) ,包括创建、调度、消亡的整个过程;由内核管理,包含独立的地址空间、PCB(进程控制块)、文件描述符表等,是操作系统资源分配的最小单位

1.2 进程相关命令

1.2.1 top

  • 作用动态实时查看所有进程任务信息,按 CPU / 内存占用率排序
  • 核心字段
    • PID:进程唯一 ID(值 > 0)
    • PPID:父进程 ID
    • % CPU:进程占用 CPU 百分比
    • % MEM:进程占用内存百分比
    • COMMAND:进程对应的命令 / 程序名
  • 常用操作:P 按 CPU 排序、按 M 按内存排序、按 q 退出

如下图所示:

1.2.2 ps -ef

  • 作用 :查看当前系统中所有进程任务的完整信息(标准格式,包含 UID、PPID 等)
  • 格式解读
    • UID:进程所属用户 ID
    • PID:进程 ID
    • PPID:父进程 ID
    • C:CPU 占用率
    • STIME:进程启动时间
    • TTY:进程关联的终端(? 表示无终端)
    • TIME:进程占用 CPU 总时间
    • CMD:进程命令
  • 实用用法ps -ef | grep 进程名 ------ 过滤查找指定进程(注意: grep 自身会匹配出一条,可加 | grep -v grep 排除)

如下图所示:

1.2.3 ps -aux

  • 作用 :查看进程信息(进程状态)
  • 核心字段
    • USER:进程所属用户
    • PID:进程 ID
    • % CPU:CPU 占用百分比
    • % MEM:内存占用百分比
    • VSZ:虚拟内存大小(KB)
    • RSS:物理内存占用(KB)
    • STAT:进程状态(R 运行、S 睡眠、Z 僵尸、T 停止等)
    • COMMAND:进程命令
  • 实用用法ps -aux | grep 进程名 ------ 比 ps -ef 更直观看到资源占用

如下图所示:

1.2.4 kill

  • 作用:向进程发送信号,实现终止 / 暂停等操作(默认发送 15 号终止信号,-9 为强制杀死)
  • 常用用法
    • kill 进程PID:发送 15 号信号(SIGTERM),让进程优雅退出(可被进程自身忽略)
    • kill -9 进程PID:发送 9 号信号(SIGKILL),强制杀死进程(无法忽略,慎用)
    • killall -9 进程名:按进程名强制杀死所有同名进程

1.2.5 &

  • 作用 :执行命令时,将任务放到后台运行(终端可继续输入其他命令)
  • 用法./a.out &
  • 注意:后台进程仍与当前终端关联,终端关闭则进程可能终止

1.2.6 ps

  • 作用 :查看当前终端下由当前用户启动的所有前后台进程(不含完整信息)
  • 补充ps -l 可查看当前终端进程的详细信息(含优先级、状态等)

如下图所示:

1.2.7 jobs

  • 作用 :查看当前终端下的所有后台 / 暂停任务,并显示任务编号(%1、%2...)
  • 核心字段
    • 任务编号:如 12
    • 状态:Running(运行)、Stopped(暂停)
    • 命令:任务对应的命令
  • 用法 :直接输入 jobs 即可,常用参数 jobs -l 可同时显示进程 PID

1.2.8 fg 编号

  • 作用 :将后台运行 / 暂停的任务调至前台执行
  • 用法
    • fg 1fg %1:将编号 1 的后台任务调到前台
    • 若只有一个后台任务,直接 fg 即可(无需编号)

1.2.9 nice

  • 作用启动进程时指定其优先级(Linux 优先级范围:-20(最高) ~ 19(最低),默认 0)
  • 用法nice -n 优先级 命令
    • 例:nice -n 10 ./a.out ------ 以优先级 10 启动 a.out(更低优先级,占用 CPU 更少)
    • 例:nice -n -5 ./a.out ------ 以优先级 - 5 启动(更高优先级,需 root 权限)
  • 注意:普通用户只能设置 0~19,负优先级(-20~-1)需 root 权限

1.2.10 renice

  • 作用修改正在运行的进程的优先级
  • 用法renice -n 优先级 进程PID
    • 例:renice -n 5 12345 ------ 将 PID 为 12345 的进程优先级改为 5
  • 注意
    • 普通用户只能调高自身进程的优先级(如从 0→5),不能调低;root 可任意修改
    • 优先级范围同 nice:-20 ~ 19

1.3 进程的创建

虚拟地址:MMU(内存管理单元)将物理地址映射后的可以访问的地址空间

物理地址:硬件RAM的实际空间地址,用户一般不允许直接访问物理地址,要通过MMU映射为虚拟地址再进行访问

虚拟地址空间分布:

每个进程执行,操作系统会为进程分配0-4G虚拟内存空间

0-3G(用户空间) 3-4G(内核空间)

  • 文本段(.text):只读,存放代码和相关指令
  • 数据段:
    • 存放字符串常量(.rodata)
    • 已初始化全局/静态变量(.data):在编译时分配空间,程序运行时加载到内存空间中
    • 未初始化全局/静态变量(.bss):(编译时不占空间,运行时分配并初始化为 0)在进程启动后由进程默认初始化为0值
  • 栈区(.stack):默认8M,存放局部变量、函数参数、返回地址,未经初始化值为随机值,超过变量作用域自动回收变量空间,增长方向自高向低增长
  • 堆区(.heap):剩余的空间为堆区,可以由程序员手动申请释放,增长方向自低向高增长
  • 内核:所有进程共享,存放内核代码 / 数据,用户无法访问

1.4 多个进程的空间(进程空间是独立的)

  • 每个进程都有独立的 0~4G 虚拟地址空间 (虚拟地址值可重复),MMU 会将不同进程的虚拟地址映射到不同的物理地址空间
  • 例:进程 1 和进程 2 的虚拟地址 0x1000,MMU 会映射到物理内存的不同位置(如 0x80000000 和 0x90000000),保证进程间内存隔离。
  • 多进程共用同一虚拟地址空间,但物理是独立的

1.5 进程的调度

  • 核心原则:操作系统内核的进程调度器负责分配 CPU 资源,目标是 "公平 + 高效利用 CPU"。
  • 核心特点:宏观并行(用户看多个进程同时运行),微观串行(CPU 核心同一时间只执行一个进程)
  • 常见调度算法
    1. 先来先服务(FCFS)(先来先执行,后来后执行):按进程到达顺序调度,优点简单,缺点 "饥饿"(长进程阻塞短进程)。
    2. 短作业优先(SJF):优先调度运行时间短的进程,减少平均等待时间,缺点 "长作业饥饿"、需预估作业时长。
    3. 高优先级调度:优先级高的进程先执行(Linux 优先级:-20 最高,19 最低),分为:
      • 非抢占式:高优先级进程需等当前进程执行完 / 主动放弃 CPU;
      • 抢占式:高优先级进程可打断当前进程(Linux 默认)。
    4. 时间片轮转(RR):普通进程默认用,时间片 5~10ms,宏观并行(用户感知同时运行),微观串行(CPU 单核同一时间仅执行一个进程)。就绪队列中的进程轮流占用 CPU,时间片到则切换到下一个进程,保证公平性。
    5. 多级队列反馈调度:结合优先级 + 时间片,不同优先级队列用不同时间片(高优先级时间片短),进程执行超时则降级到低优先级队列,兼顾公平与效率。
    6. 负载均衡调度:多 CPU / 多核场景,将进程调度到负载低的 CPU 核心,提升整体利用率。

1.6 进程的状态

运行态(R):任务正在被CPU执行

就绪态(R):任务正在处于就绪队列中,但未被CPU调度到

可唤醒等待态(S):任务等待某个资源被CPU挂起,等待过程中可以被唤醒

不可唤醒等待态(D):任务等待某个资源被CPU挂起,等待过程不能被打断;D 状态进程不能被 kill -9 终止,只能等其完成 IO 或重启系统

停止态(T):用户将某个任务暂停

僵尸态(Z):进程执行结束,空间未被回收;父进程未调用 wait/waitpid 回收资源;僵尸态(Z)只能通过杀死父进程解决

结束态(X):进程执行结束,空间也被回收

1.7、进程相关的函数接口

1.7.1 fork

  • 函数原型
cpp 复制代码
#include <unistd.h> // 头文件必须补充
pid_t fork(void);
  • 功能 :创建一个新的子进程,子进程是父进程的 "副本";调用一次,返回两次(父 / 子进程各返回一次)。
  • 参数:缺省
  • 返回值
    • 父进程:返回子进程的 PID(>0);
    • 子进程:返回0
    • 失败:返回 -1(如系统进程数达到上限),并设置 errno。
  • 内存拷贝机制

子进程会拷贝父进程的文本段(代码)、数据段(静态变量、全局变量、字符串常量)、堆区(malloc)、栈区(局部变量)

  • 执行逻辑 :fork 成功后,父子进程从 fork 的下一行代码开始并发执行(谁先执行由操作系统调度决定)。
  • 示例代码:
cpp 复制代码
#include <stdio.h>
#include <unistd.h>

int main() {
    int a = 10;
    pid_t pid = fork(); // 调用一次,返回两次

    if (pid > 0) {
        // 父进程执行区
        a = 20;
        printf("父进程:PID=%d,子进程PID=%d,a=%d\n", getpid(), pid, a);
    } else if (pid == 0) {
        // 子进程执行区
        a = 30;
        printf("子进程:PID=%d,父进程PID=%d,a=%d\n", getpid(), getppid(), a);
    } else {
        perror("fork失败"); // 打印错误原因
        return -1;
    }
    return 0;
}

1.7.2 getpid

  • 函数原型
cpp 复制代码
#include <unistd.h>
pid_t getpid(void);
  • 功能 :获取当前调用进程的 PID(进程唯一标识)。
  • 参数:缺省
  • 返回值:成功返回当前进程的 PID(始终 > 0);无失败场景。
  • 使用场景:打印进程 ID、区分父子进程等。

1.7.3 getppid

  • 函数原型
cpp 复制代码
#include <unistd.h>
pid_t getppid(void);
  • 功能 :获取当前调用进程的父进程的 PID。
  • 参数:缺省
  • 返回值:成功返回父进程 PID;无失败场景。
  • 易错点:若父进程先于子进程退出,子进程会被 init 进程(PID=1)收养,此时子进程调用 getppid () 会返回 1。
相关推荐
A小辣椒10 小时前
TShark:Wireshark CLI 功能
linux
A小辣椒14 小时前
TShark:基础知识
linux
AlfredZhao16 小时前
OCI 明明分配了 200G 系统盘,为什么 df 只看到 30G?
linux·oci
AlfredZhao1 天前
vi 删除指定范围的行,不用再反复按 dd
linux·vi
用户9718356334662 天前
银河麒麟 KY10 申威(SW64) 安装 nginx-1.16.1-2.p01.ky10.sw_64.rpm 详细步骤
linux
猪脚踏浪2 天前
linux 拷贝文件或目录到指定的位置
linux
摇滚侠2 天前
Linux CentOS7 rpm 安装 MySQL 5.7
linux·运维·mysql
bush42 天前
嵌入式linux学习记录十四、术语
linux·嵌入式
载数而行5202 天前
Linux 11 动态监控指令top
linux
不会C语言的男孩2 天前
Linux 系统编程 · 第 8 章:进程基础
linux·c语言