当前位置: 首页 > 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.dtcms.com/a/288638.html

相关文章:

  • 30天打牢数模基础-决策树讲解
  • Linux入门篇学习——NFS 服务器的搭建和使用和开发板固件烧录
  • Spring Boot 第一天知识汇总
  • 【Java项目安全基石】登录认证实战:Session/Token/JWT用户校验机制深度解析
  • 相似度计算
  • 「Java案例」利用方法求反素数
  • Facebook 开源多季节性时间序列数据预测工具:Prophet 饱和预测 Saturating Forecasts
  • dynamic_cast的实现原理
  • Beamer-LaTeX学习(教程批注版)【6】
  • Elasticsearch 简化指南:GCP Google Compute Engine
  • GPT-4o mini TTS:领先的文本转语音技术
  • 随着GPT-5测试中泄露OpenAI 预计将很快发布 揭秘GPT-5冲击波:OpenAI如何颠覆AI战场,碾压谷歌和Claude?
  • prometheus 黑盒监控和docker检测
  • mysql第三次作业
  • 学习寄存器——GPIO(二)学习BSRR BRR ODR寄存器的原子性和在HAL库的应用
  • 【Go语言-Day 22】解耦与多态的基石:深入理解 Go 接口 (Interface) 的核心概念
  • 【详细笔记】两类曲线积分转换
  • 群组功能实现指南:从数据库设计到前后端交互,上班第二周
  • 【数据结构】揭秘二叉树与堆--用C语言实现堆
  • 人工智能之数学基础:随机实验、样本空间、随机事件
  • Docker Desktop 入门教程(Windows macOS)
  • 深度学习图像分类数据集—百种病虫害分类
  • Python绘图小工具开发:从零构建数据可视化利器
  • 股票及金融笔记
  • 如何升级Docker部署的Dify
  • Materials Studio学习笔记(二十九)——尿素的几何优化
  • 私有云新势力:Puter+CPolar如何低成本替代商业网盘?
  • 【Linux性能优化】常用工具和实战指令
  • 小架构step系列20:请求和响应的扩展点
  • 制作mac 系统U盘