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

系统编程day03-进程

1.进程

1.1程序和进程的区别

程序:代码或者指令的有序堆叠,是静态的,存放在磁盘空间。

进程:程序的运行实例,进程是动态的

1.2单道程序和多道程序

单道程序:所有进程一个一个排队执行。若 A 阻塞,B 只能等待,即使 CPU 处于空闲状态。而在人机交互时阻塞的出现是必然的。所有这种模型在系统资源利用上及其不合理,在计算机发展历史上存在不久,大部分便被淘汰了。(例如一开始的dos系统)

多道程序:在计算机内存中同时存放几道相互独立的程序,它们在管理程序控制之下,相互穿插的运行

1.3并发和并行

并行(一定是多核的):多道程序同时在多个处理器上运行。

并发:宏观上的并行,并不是真正的并行,而是基于多道程序设计的一种根据时间片轮换cpu使用权的一种特殊机制。

1.4进程控制块

PCB:process-control-block

进程运行时,内核为进程每个进程分配一个 PCB(进程控制块),维护进程相关的信息,Linux 内核的进程控制块是 task_struct 结构体。

查看这个结构体:

PCB:

2.进程的状态

2.1进程的三种状态

就绪状态:准备完毕,等待执行

运行状态:获得CPU资源,正在使用

等待状态:当有事情发生,条件不满足,需要重新准备

2.2进程状态的查看

ps:ps可以查看进程信息

可以结合命令参数:

-a 显示终端上的所有进程,包括其他用户的进程
-u 显示进程的详细状态
-x 显示没有控制终端的进程
-w 显示加宽,以便显示更多的信息
-r 只显示正在运行的进程
-ajx 更深层次的进程信息

ps -aux 相当于Linux中的任务管理器

stat的参数意义如下:

3.进程号

3.1什么是进程号

每个进程都由一个进程号(pid)来标识,其类型为 pid_t(整型),进程号的范围:0~32767。进程号总是唯一的,但进程号可以重用。当一个进程终止后,其进程号就可以再次使用。

两个特殊进程:

  • 0进程:

    • 早期叫做:交换进程

    • 现在叫做:空闲进程(当CPU空闲的时候,会执行这个进程)

  • 1进程:init进程,是所有用户进程的祖先(所有用户进程都是有1号进程直接或者间接创建)。(1号进程由0号进程创建)

pid:进程的编号

ppid:父进程,每一个进程都是由父进程创建而来的。ppid就是父进程的编号。

pgid:进程组,一个或者多个进程的集合,这些进程的集合称为进程组,进程组有一个组号,叫做pgid。这些进程相互关联,可以接收终端传来的各种信号。

3.2获取进程的函数

getpid

获取当前进程的进程号

#include <sys/types.h>
#include <unistd.h>
pid_t getpid(void);

返回值:获取的当前进程的进程号,pid_t

参数:无参数

getppid

#include <sys/types.h>
#include <unistd.h>
pid_t getppid(void);

返回值:获取的当前进程的父进程号,pid_t

参数:无参数

getpgid

#include <sys/types.h>
#include <unistd.h>
pid_t getpgid(pid_t pid);

返回值:获取的pid进程的进程组号,pid_t

参数:需要传入要找的pid号

4.进程的创建

4.1进程的创建函数

进程的创建由fork函数来完成。

fork函数:

#include <sys/types.h>
#include <unistd.h>pid_t fork(void);

函数功能:创建一个新的进程。这个被创建的新的进程叫做子进程,是调用fork函数这个进程(父进程)的子进程。

返回值:

如果创建成功:

  • 在父进程中返回的是子进程的id

  • 在子进程中返回的是0

如果创建失败:

  • 返回-1

4.2父子进程的关系

子进程是父进程的一个复制品(从fork的下一句开始复制),两个进程都有各自单独的空间。

这里说的fork的下一句并不是if(pid == -1);而是fork函数创建子进程完后,进行的赋值操作。

最终的终端打印结果如上,一个是在父进程中进行,一个是在子进程中进行。

子进程从父进程那里继承了整个进程的地址空间。

地址空间:包括进程上下文、进程堆栈、打开的文件描述符等。

子进程所独有的只有它的进程号,计时器等。因此,使用 fork 函数的代价是很大的。

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>int main(int argc, char const *argv[])
{pid_t pid = fork();if (pid == -1){perror("fork");return 0;}else if (pid > 0){printf("hello,welcome to parent process\n");printf("当前进程id%d,他的子进程id%d\n", getpid(), pid);}else if (pid == 0){printf("hello,welcome to child process\n");printf("子进程pid:%d,他的父进程id:%d\n", getpid(), getppid());}return 0;
}

拓展1:sleep函数

#include <unistd.h>
unsigned int sleep(unsigned int seconds);

函数功能:将进程挂起(休眠)一段时间。

返回值:

  • 如果sleep函数里面的seconds走完了,那么返回0

  • 如果没有休眠完,被强制打断,那么返回剩余待休眠的时间

参数:挂起或者休眠的时间

拓展2:全缓冲与行缓冲

全缓冲:缓冲区满了以后强制进行刷新,即write函数可以将数据输出到终端

行缓冲:遇到\r\n,进行刷新,此时write函数可以将数据输出到终端

拓展3:exit函数 与 _exit函数

exit函数:

功能:库函数,将进程相关数据 清理后退出

除了调用_exit函数还会调用一个清理函数

所以使用exit函数的运行效率比较低

#include <stdlib.h>
void exit(int status);

_exit函数:

功能:系统调用函数,将进程直接退出,不进行清理

void _exit(int status);

5.进程资源回收

在每个进程退出的时候,内核释放该进程所有的资源、包括打开的文件、占用的内存等。但是仍然为其保留一定的信息,这些信息主要主要指进程控制块 PCB 的信息(包括进程号、退出状态、运行时间等)。 父进程可以通过调用 wait 或waitpid 得到它的退出状态同时彻底清除掉这个进程。

5.1wait函数

#include <sys/types.h>
#include <sys/wait.h>
pid_t wait(int *status)

函数功能:等待任意一个子进程结束,如果任意一个子进程结束了,此函数会回收该子进程的资源。

参数:

status : 进程退出时的状态信息,是一个指针

返回值:

  • 成功:返回运行结束的进程的进程号

  • 失败:-1

代码案例:

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <sys/wait.h>int main(int argc, char const *argv[])
{pid_t pid = fork();if (pid == -1){perror("fork");return 0;}else if (pid == 0){for (int i = 1; i <= 5; i++){printf("我还能再玩%ds\n", 5 - i);sleep(1);}_exit(0);}else if (pid > 0){int status = 0;printf("你5s以后必须停止玩游戏\n");sleep(5);wait(&status); //阻塞,等待子进程退出if (WIFEXITED(status) != 0){printf("status:%d\n", WEXITSTATUS(status));if (WEXITSTATUS(status)==0){printf("好的,你说的对,听你的\n");}else if (WEXITSTATUS(status)==1){printf("好的,你说的不对,但是我还是听你的\n");}}}return 0;
}

查看WEXITSTATUS函数的定义可以看出来,她是将status中除了8-15位的其他位数全部置零,并且向右偏移了8位。可以取到status具体的值。

5.2waitpid函数

waitpid() 是 Unix/Linux 系统中用于进程同步的核心系统调用,专门用于父进程等待特定子进程的状态变化。相比通用的 waitpid(),它提供了更精细的控制能力

函数原型:

#include <sys/types.h>
#include <sys/wait.h>pid_t waitpid(pid_t pid, int *status, int options);

参数解释:

1.pid :目标子进程标识

  • >0:等待指定PID的子进程
  • -1:等待任意子进程(等效于wait())
  • 0:等待同进程组的任意子进程
  • <-1:等待进程组ID等于|pid|的任意子进程

2.status:状态信息指针:

  • 存储子进程退出状态(使用宏解析)
  • 可设为NULL(不关心退出详情)

3.option:控制选项(位掩码)

  • 0:阻塞等待(默认行为)
  • WNOHANG:非阻塞模式(立即返回)
  • WUNTRACED:报告已经停止的子进程
  • WCONTINUED:报告已经继续执行的被停止子进程

返回值:

  • 成功:返回状态变化的子进程PID
  • 无状态变化:返回0
  • 错误:返回-1
    http://www.xdnf.cn/news/19936.html

    相关文章:

  1. ​​​​​​​2025企业级GEO优化白皮书:技术生态与商业落地双轮驱动下的选择指南
  2. 【2025ICCV】基于 ​CL-Splats​ 的3D高斯溅射模型
  3. 苍穹外卖项目笔记day04--Redis入门
  4. 如何区分 Context Engineering 与 Prompt Engineering
  5. 【2025ICCV-持续学习方向】一种用于提示持续学习(Prompt-based Continual Learning, PCL)的新方法
  6. C 内存对齐踩坑记录
  7. 如何批量在PDF文档最后一页盖章?
  8. 从源码入手,详解Linux进程
  9. 并发编程指南 同步操作与强制排序
  10. 理解Go与Python中的闭包(Closure)
  11. 充电枪结构-常规特征设计
  12. 代码随想录刷题Day48
  13. PostgreSQL 索引使用分析2
  14. 权威认证!华宇TAS应用中间件获得商用密码产品认证证书
  15. 深入解析Go语言切片(Slice)精髓
  16. 【论文阅读】LightThinker: Thinking Step-by-Step Compression (EMNLP 2025)
  17. 金额字段该怎么设计?——给小白的超详细指南(含示例 SQL)
  18. UniApp 混合开发:Plus API 从基础到7大核心场景实战的完整指南
  19. 一文吃透 Protobuf “Editions” 模式从概念、语法到迁移与实战
  20. 自动化仓库托盘搬运减少错误和损坏的方法有哪些?实操案例解读
  21. 【踩坑记录】Unity 项目中 PlasticSCM 掩蔽列表引发的 文件缺失问题排查与解决
  22. 分割回文串手绘图
  23. 【OpenGL】LearnOpenGL学习笔记19 - 几何着色器 Geometry Shader
  24. 解决 Android Studio 中 build 目录已被 Git 跟踪后的忽略问题
  25. 【stm32】定时器中断与定时器外部时钟
  26. el-table 行高亮,点击行改变背景
  27. CVE-2025-6507(CVSS 9.8):H2O-3严重漏洞威胁机器学习安全
  28. 安全测试漫谈:如何利用X-Forwarded-For头进行IP欺骗与防护
  29. TDengine NOW() 函数用户使用手册
  30. Ubuntu环境下的 RabbitMQ 安装与配置详细教程