当前位置: 首页 > news >正文

操作系统——进程

在操作系统的世界里,进程是一个核心概念。无论是我们日常使用的图形界面程序,还是服务器后台运行的服务,本质上都是一个个进程在工作。本文将从进程的基本含义出发,逐步深入探讨进程与程序的区别、进程的状态、调度机制,以及如何在 Linux 中操作进程,最后通过实践案例帮助你巩固所学知识。

一、进程的含义:程序的 "动态人生"

简单来说,进程是程序的执行过程。当我们双击一个应用程序(比如浏览器),或者在终端运行./a.out时,操作系统会为这个程序分配内存资源、CPU 时间片等,这个 "活动" 的过程就是进程。

进程的所有信息都被记录在一个名为PCB(Process Control Block,进程控制块) 的结构体中(在 Linux 中对应的结构体是task_struct)。可以把 PCB 理解为进程的 "身份证 + 档案",包含了进程运行所需的全部关键信息:

  • PID(Process ID,进程标识符):每个进程的唯一编号,就像人的身份证号。
  • 当前工作路径:进程的 "工作目录",可通过chdir系统调用修改。
  • umask:文件创建时的默认权限掩码(比如默认0002,表示新文件权限会去掉其他用户的写权限)。
  • 打开的文件列表:进程已打开的文件描述符,包括普通文件、管道、设备等。
  • 信号相关设置:如何处理异步事件(比如Ctrl+C发送的终止信号)。
  • 用户 ID 和组 ID:标识进程的所属用户和用户组,用于权限控制。
  • 资源上限:进程能使用的系统资源上限(可通过ulimit -a查看,比如最大打开文件数、最大内存使用量等)。

二、进程与程序:动态与静态的博弈

很多人会混淆 "进程" 和 "程序",其实两者的核心区别在于 "动态" 与 "静态":

维度程序进程
存在形式静态:存储在硬盘中的代码和数据集合动态:程序的执行过程(创建→调度→消亡)
生命周期永存:只要不删除,就一直存在暂时:从启动到结束,有明确的生命周期
状态变化无:始终是固定的代码和数据有:运行、暂停、阻塞等状态切换
资源占用不占用 CPU、内存等运行时资源占用 CPU、内存、文件描述符等资源
并发能力无:无法同时 "运行" 多个副本有:多个进程可并发执行

举个例子:我们编写的test.c编译后生成a.out(这是程序,静态存储在硬盘);当执行./a.out时,操作系统会创建一个进程(有唯一 PID),这个进程就是a.out的动态执行过程。

一个程序可以生成多个进程(比如多次运行./a.out,会得到多个 PID 不同的进程);一个进程也可以执行多个程序(比如通过exec系列函数切换执行的程序)。

三、进程的核心作用:实现 "同时" 做更多事

进程的核心价值是实现并发—— 让计算机 "看起来" 能同时运行多个任务。比如我们可以一边用微信发消息,一边用浏览器查资料,这背后就是多个进程在协同工作。

这里需要区分两个容易混淆的概念:

  • 并发:宏观上多个任务同时进行,但微观上 CPU 通过快速切换任务(上下文切换)实现,同一时刻只有一个任务在执行(比如单 CPU 系统)。
  • 并行:微观上多个任务真正同时执行,需要多个 CPU 核心(比如双核心 CPU 可同时运行两个进程)。

举个代码例子:如果我们想同时处理 "上下左右按键输入" 和 "发送视频",单线程循环嵌套无法实现(会陷入内层循环无法跳出),但通过两个进程分别处理,就能实现 "同时进行":

// 伪代码:两个进程分别处理不同任务
// 进程1:处理上下左右输入
while(1){检测上下左右按键;响应按键操作;
}// 进程2:发送视频
while(1){采集视频数据;发送视频;
}

四、进程的状态:从诞生到消亡的 "人生阶段"

进程的生命周期中会经历多种状态,不同操作系统对状态的划分略有差异:

1. 基本操作系统的三状态模型

  • 就绪态:进程已获取除 CPU 外的所有资源,等待 CPU 调度。
  • 执行态:进程正在 CPU 上执行代码。
  • 阻塞态:进程因等待资源(比如等待键盘输入、文件读取完成)而暂停,即使分配 CPU 也无法执行。

2. Linux 中的进程状态

Linux 对进程状态的划分更细致,通过ps aux可查看进程状态:

  • R(运行态):包括正在 CPU 执行和处于就绪态的进程(等待 CPU 调度)。
  • S(可唤醒睡眠态):进程等待资源,但可被信号唤醒(比如等待键盘输入时,Ctrl+C可终止)。
  • D(不可唤醒睡眠态):进程等待关键资源(比如磁盘 I/O),不可被信号唤醒(避免数据不一致)。
  • T(暂停态):进程被暂停(比如收到SIGSTOP信号,可通过SIGCONT恢复)。
  • Z(僵尸态):进程已结束,但父进程未回收其资源(PCB 仍存在),需父进程调用wait系列函数清理。

五、进程调度:操作系统的 "指挥家"

操作系统的核心功能之一是进程调度—— 决定哪个进程获取 CPU 资源,以及运行多长时间。调度的目标是提高系统吞吐量、减少响应时间,不同场景采用不同算法:

1. 调度算法分类

  • 实时系统(要求任务在规定时间内完成):

    • FIFO(先来先服务):按请求顺序调度,适合长任务。
    • RR(时间片轮转):为每个任务分配固定时间片,超时后切换,适合短任务。
    • 短任务优先:优先调度运行时间短的任务,减少平均等待时间。
  • 分时系统(不保证严格时间限制,注重交互响应):

    • 时间片轮询:每个进程轮流获得 CPU 时间片(比如 10ms),宏观上 "同时" 运行。
    • 优先级调度:高优先级进程先执行(优先级可动态调整,避免低优先级进程饿死)。

2. 上下文切换

当调度器切换进程时,需要保存当前进程的状态(CPU 寄存器、内存映射等),加载新进程的状态,这个过程称为上下文切换。虽然上下文切换会消耗资源,但正是通过这种切换,才能实现多进程并发。

六、Linux 中查询进程的常用命令

在 Linux 中,我们可以通过以下命令查看和管理进程:

  1. ps aux:查看系统中所有进程的详细信息,包括:

    • 状态(R/S/D/T/Z)、PID、PPID(父进程 ID)、CPU 占用率、内存占用等。
    • 示例:ps aux | grep a.out 可筛选出名为a.out的进程。
  2. top:动态显示进程状态(默认每秒刷新),按 CPU / 内存占用排序,适合监控系统负载。

  3. killkillall:发送信号控制进程:

    • kill -2 PID:发送SIGINT信号(相当于Ctrl+C),请求进程终止。
    • kill -9 PID:发送SIGKILL信号,强制终止进程(进程无法忽略)。
    • killall -9 进程名:终止所有同名进程(比如killall -9 a.out)。

七、进程操作的核心函数(原语)

在 C 语言中,我们可以通过系统调用直接操作进程,最核心的是forkgetpidgetppid

  1. fork():创建子进程,特点是 "一次调用,两次返回":

    • 父进程中返回子进程的 PID(>0)。
    • 子进程中返回 0。
    • 子进程是父进程的副本(复制用户空间和 PCB,但 PID 不同),变量不共享(各自有独立内存空间)。
    • 示例:

      #include <stdio.h>
      #include <unistd.h>int main() {pid_t pid = fork();if (pid > 0) {printf("父进程:PID=%d,子进程PID=%d\n", getpid(), pid);} else if (pid == 0) {printf("子进程:PID=%d,父进程PID=%d\n", getpid(), getppid());}return 0;
      }
      
  2. getpid():获取当前进程的 PID。

  3. getppid():获取当前进程的父进程 PID。

八、实践练习:动手操作进程

练习 1:两个进程向同一文件写入数据

编写程序,创建父进程和子进程,分别向1.txt写入带时间戳和 PID 的信息:

#include <stdio.h>
#include <unistd.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>int main() {int fd = open("1.txt", O_WRONLY | O_CREAT | O_APPEND, 0644);pid_t pid = fork();if (pid > 0) { // 父进程while (1) {time_t t = time(NULL);char* time_str = ctime(&t);char buf[100];sprintf(buf, "父进程 %d:%s", getpid(), time_str);write(fd, buf, strlen(buf));sleep(2); // 每2秒写一次}} else if (pid == 0) { // 子进程while (1) {time_t t = time(NULL);char* time_str = ctime(&t);char buf[100];sprintf(buf, "子进程 %d:%s", getpid(), time_str);write(fd, buf, strlen(buf));sleep(3); // 每3秒写一次}}close(fd);return 0;
}

总结

进程是操作系统资源分配和调度的基本单位,理解进程的概念、状态、调度机制,是掌握操作系统的关键。从静态的程序到动态的进程,从单个任务到多进程并发,进程的设计让计算机能够高效地处理复杂任务。

希望通过本文的讲解和实践案例,你能对 Linux 进程有更清晰的认识。不妨动手试试文中的练习,感受进程的运行机制吧!

进程的内存

Stack   |(栈)
--------|
Share   |(共享区)So动态库/共享库
--------|
Heap    |(堆)程序原来控制 手动申请手动释放
--------|
Data    |
--------|--->数据段
Code    |

分布
0-3G(用户内存空间),是进程的空间,3G-4G是内核(内核内存空间)的空间,虚拟地址
虚拟地址*物理内存和虚拟内存的地址 映射表 1page=4kmmu(内存管理单元)

http://www.lryc.cn/news/588918.html

相关文章:

  • 前端-CSS-day4
  • CSS 高阶使用指南
  • Python 函数:从“是什么”到“怎么用”的完整指南
  • QT 中各种坑
  • 【Qt】QWidget核心属性
  • Django基础(二)———URL与映射
  • WSI中sdpc格式文件学习
  • 函数柯里化详解
  • 知识增强型Agent开发新范式:基于ERNIE-4.5的检索增强生成架构实践
  • ubuntu22.04 软创建 RAID1 与配置流程
  • Ubuntu 安装
  • Ubuntu环境下的K3S集群搭建
  • 一文读懂语义解析技术:从规则到神经网络的演进与挑战
  • DGNNet:基于双图神经网络的少样本故障诊断学习模型
  • 暑期算法训练.1
  • Linux下调试器gdb/cgdb的使用
  • 只解析了CHAME记录,如何申请免费的SSL证书
  • Linux 命令:passwd
  • WPF中ListView控件详解
  • 牛客:HJ23 删除字符串中出现次数最少的字符[华为机考][字符串]
  • Linux部署Python服务
  • langchain教程10:LCEL
  • 阿里云 Kubernetes 的 kubectl 配置
  • 深入理解设计模式之外观模式:简化复杂系统的艺术
  • 企业培训视频如何做内容加密防下载防盗录(功能点整理)
  • 优雅的Java:01.数据更新如何更优雅
  • 2025开放原子开源生态大会 | openKylin的技术跃迁和全球协作
  • 2025阿里云黑洞恢复全指南:从应急响应到长效防御的实战方案
  • CentOS服务器安装Supervisor使队列可以在后台运行
  • 2.3 数组与字符串