进程的基本概念\相关命令\创建\调度\状态及相关函数接口---软件编程---嵌入式(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...)
  • 核心字段
    • 任务编号:如 [1]、[2]
    • 状态: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。
相关推荐
小白同学_C5 小时前
Lab4-Lab: traps && MIT6.1810操作系统工程【持续更新】 _
linux·c/c++·操作系统os
今天只学一颗糖5 小时前
1、《深入理解计算机系统》--计算机系统介绍
linux·笔记·学习·系统架构
不做无法实现的梦~7 小时前
ros2实现路径规划---nav2部分
linux·stm32·嵌入式硬件·机器人·自动驾驶
默|笙9 小时前
【Linux】fd_重定向本质
linux·运维·服务器
陈苏同学9 小时前
[已解决] Solving environment: failed with repodata from current_repodata.json (python其实已经被AutoDL装好了!)
linux·python·conda
“αβ”9 小时前
网络层协议 -- ICMP协议
linux·服务器·网络·网络协议·icmp·traceroute·ping
不爱学习的老登10 小时前
Windows客户端与Linux服务器配置ssh无密码登录
linux·服务器·windows
小王C语言11 小时前
进程状态和进程优先级
linux·运维·服务器
xlp666hub11 小时前
【字符设备驱动】:从基础到实战(下)
linux·面试
弹幕教练宇宙起源12 小时前
cmake文件介绍及用法
android·linux·c++