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

[Linux]进程 / PID

一、认识进程 --- PCB

写一个死循环程序执行起来,观察进程

ps ajx        显示所有进程

用分号可以在命令行的一行中执行多条指令,也可以用 && :

ps ajx | head -1 && ps ajx | grep proc

终止掉进程后再查看:

所以 ./proc 就是死循环程序运行的进程

grep --color=auto proc 之所以一直都在,是因为命令行指令执行时也是一个进程

ps ajx | grep proc 执行时,grep 指令也变成了一个进程,查询结果自然就会包含在内

可以用 grep 的 -v 选项反向搜索来不显示这个进程:

进程可以分为两种:一是执行完就退出的,例如指令,二是用户不关就不退的,被称为常驻进程,例如杀毒软件。

二、进程属性 --- task_struct 内容分类

1. PID

PID 是进程的标示符,用于唯一标识一个进程。

可以用 getpid() 来获取进程的 PID:(需要 sys/types.h 头文件)

2.kill

kill 是一条进程相关的指令,有许多选项:

通过 -9 或 -SIGKILL 可以关闭一个进程:

kill -9 <PID>

3.  /proc

Linux 中一切皆文件,所以进程的属性也以文件的形式可供用户查看

这里以数字命名的每个目录都代表着一个进程,里面的文件都是这个进程相关的属性

其中:

(1)exe

exe 是一个链接文件,标识了这个进程来源于哪个可执行程序

如果我们删掉 proc 文件,就会变成:

注意此时进程之所以还在进行,还有这个进程的目录,是因为我们的删除操作删除掉的是磁盘中的 proc 文件,而进程是内存级的,只要不停止运行就会一直在。

(2)cwd

current work directory “当前工作目录”的缩写

进程刚刚创建时,会用自己的 cwd 属性记录下程序所在的目录作为默认的“当前路径”

如果我们在程序中用 fopen 打开一个新 log.txt 文件,运行后就会在当前路径下创建出一个 log.txt 文件。这个“当前路径”,就来自于进程的 cwd 属性。

而且这个文件被新建时,创建的路径使用的是绝对路径,是用进程的 cwd 和文件名拼接成的:/home/mmr/linux-c/par02/log.txt

想要改变进程的 cwd,可以用 chdir()

就可以把进程的 cwd 更改为根目录,log.txt 也就可以新建在根目录下了(注意普通用户没有根目录的写权限,所以普通用户会创建失败)

(3)/proc是内存级文件

/proc 并不存储在硬盘当中,关机时整个文件被释放掉,不会存储。

4.PPID

在 Linux 系统中,系统启动之后,新创建的任何进程,都是由自己的父进程创建的。

PPID 就是父进程的 PID 。

可以用 getppid() 来获取进程的 ppid

可以看到 ppid 一直是相同的,我们查看一下:

可以看到这个进程是 bash,叫做命令行解释器,是 Linux 系统的shell 外壳

命令行中,执行指令、执行程序,本质都是 bash 的进程,创建的子进程,由子进程来执行代码

用户每一次登录,系统都会为用户创建一个 bash 进程,这里 bash 前有一个 "-",代表当前这个用户是使用命令行终端进行登录的。

三、使用系统调用,创建进程 --- fork

我们运行一下:

可以看到 child proc 打印了两遍。

这是因为 fork 创建出子进程后,原先的进程和子进程都要运行。原先的进程的父进程是 bash,子进程的父进程是原先的进程。

这两个进程先后连续创建的,所以 pid 也是连续的。

由 fork 的返回值可以知道,如果子进程创建成功,那么在原先的进程中,获得的返回值是子进程的 pid,而子进程中获得的 fork 返回值是 0

fork 创建的子进程,与其父进程共享同一份代码,但是数据是各自私有一份的,互不干扰。

父进程的代码,是由硬盘加载进内存后运行的,而子进程的代码,是直接共享自父进程的,而非从硬盘中加载得来。

所以说,进程具有很强的独立性。

多个进程之间,运行时,是互不影响的。

四、创建多个进程

1. C++

Linux 中 C++ 可以使用 .cpp .cc .cxx 作为后缀

使用 g++ -o <程序名> <源文件名> 生成可执行程序

如果使用了C++11中的语法:

2.创建多个进程

为什么这里子进程的 PPID 是 1 ?

因为我截这个图时父进程已经执行完毕挂掉了,此时子进程的 PPID 就不会是原先的父进程,会被 init 进程,托管给 1 号进程。

五、再理解创建子进程

1. fork 函数为什么有两个返回值

在 fork 函数体内部,先是父进程在走,在走的时候,子进程被创建出来,因为父子进程是共享同一份代码的,所以这时候就是父子进程一起在走 fork 函数。

当 fork 函数运行到最后的 return 语句时,父子进程各自执行一次 return,父进程返回父进程的值,子进程返回子进程的值。又因为父子进程的数据是各自私有一份的,所以即使返回值不同也互不干预,不会有任何后果。

因此虽然一个函数有两个返回值,但其实并不冲突。

2. fork之后,父子谁先运行

fork之后,父子进程谁先运行是不确定的,是由OS的调度器自主决定的。

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

相关文章:

  • 【开源项目】基于RuoYi-Vue-Plus的开源进销存管理系统
  • Spring Boot 配置文件解析
  • USB技术发展史:从1.0到USB4的演进之路
  • Matplotlib Contourf 标注字体详细设置
  • Spring之AOP面向切面编程详解
  • 【数据结构】双向循环链表的实现
  • MyBatis从浅入深
  • day24——Java高级技术深度解析:单元测试、反射、注解与动态代理
  • 高性能熔断限流实现:Spring Cloud Gateway 在电商系统的实战优化
  • `SearchTransportService` 是 **协调节点与数据节点之间“搜索子请求”通信的运输层**
  • 4种快速创建SpringBoot项目的方法
  • Claude Code 逆向工程分析,探索最新Agent设计
  • JavaScript 中Object、Array 和 String的常用方法
  • 金融工程、金融与经济学知识点
  • 数据结构与算法汇总
  • 连接语言大模型(LLM)服务进行对话
  • GaussDB select into和insert into的用法
  • 机器学习基础:从数据到智能的入门指南
  • python生成密钥
  • Self-Consistency:跨学科一致性的理论与AI推理的可靠性基石
  • An End-to-End Attention-Based Approach for Learning on Graphs NC 2025
  • JAVA面试宝典 -《API设计:RESTful 与 GraphQL 对比实践》
  • 《通信原理》学习笔记——第五章
  • 【1】YOLOv13 AI大模型-可视化图形用户(GUI)界面系统开发
  • Openlayers 面试题及答案180道(121-140)
  • 让不符合要求的任何电脑升级Windows11
  • 【LeetCode数据结构】单链表的应用——环形链表问题详解
  • WireShark抓包分析TCP数据传输过程与内容详解
  • 使用Qt6 QML/C++ 和CMake构建海康威视摄像头应用(代码开源)
  • 【GameMaker】GML v3 的现行提案