[Linux] 系统进程相关概念、系统调用、Linux进程详析、进程查看、fork()初识
进程相关概念
什么是进程?
运行起来的程序就是进程
运行起来的程序就是进程, 这句话并不准确。
PCB
进程的属性:PCB
PCB 即 Process Control Block, 意为 进程控制块
当一个程序被运行时, 操作系统会自动生成一个PCB 并与程序结合 作为一个进程加载到内存中
struct task_struct{}
是一个结构体Linux中的PCB
struct task_struct{}
- 进程标识符
- 进程状态
- 进程优先级
- 内存指针
- 上下文数据
- I/O状态信息
- …………
Linux进程
* 系统调用
系统调用
系统调用
而 Linux系统的内核是用C语言写的, Linux的系统调用本质上其实是C语言的函数调用
Linux进程查看
1. ps
#include <iostream>
#include <unistd.h>
using std::cout;
using std::end;
int main() {
while() {
cout << "I am a Process" << endl;
sleep(1);
}
return 0;
}
ps ajx | grep "AMProcess"
搜索进程:(暂时忽略前面的数字)
使用
ps ajx | grep "AMProcess"
指令之后, 可以看到第一个进程就是我们程序的进程, 那么第二个相关的进程是什么呢?我们自己编写的程序运行之后, 加载到内存中成为了一个进程
在查找进程时, 我们使用了 grep指令来查找与AMProcess相关, 而grep其实也是一个程序, 使用grep 即 将grep运行了此时grep也就加载到内存中成为了一个程序, 此时grep又是用来查找AMProcess相关的, 所以进程中的 grep进程包含一个AMProcess关键词
当 再次基础上 使用
| grep -v grep
排除 grep相关进程之后:可以发现, 此时ps展示的只有 AMProcess程序运行之后成为的进程
2. 进入/proc路径
/
路径下这些数字是进程的 PID
当前路径
-
exe
, 此文件表示了此进程的可执行文件的所在路径 -
cwd
, 此文件则表示了此进程当前所运行的路径
, 简称为当前路径
(此当前路径与目录的当前路径不同)即,
当前路径
其实是指此进程所运行的路径, 而不是可执行程序的路径
PID 和 PPID
PID
Process ID, 简称PID
. 每个进程的PID
是唯一的, 用来表示此进程, 就像每个人都有一个全国唯一的身份证号一样进程的PID 也可以用ps查看
ps ajx | head
将头栏显示出来, 就可以知道哪一栏是进程的PID了:ps ajx
查看系统进程的时候, 第2列 就表示进程的 PIDps ajx | head -1 && ps ajx | grep "AMProcess" | grep -v grep
):AMProcess进程被kill掉, 当再次运行AMProcess程序时:
发现, 此程序在系统中的进程的PID已经不再是 23668, 而是 5359, /proc 路径下也没有了 23668, 却有 5359
这表明, 每次运行相同的程序而生成的进程的PID是不固定的
getpid() 获取PID
ps ajx | head
指令获取头栏 然后得出PID的方法之外, Linux提供了系统调用可以在程序中得到PID查看系统调用可以用 man 2或3 系统调用 指令来查看, 但是在使用 man 2或3 之前, 需要安装 man-pages
CentOS 下的指令是
sudo yum install man-pages
如果是
openEuler
相关系统, 还需要安装man-pages-help
, 即执行sudo yum install man-pages-help
PPID
PPID 其实是 Parent Process ID, 即 父进程的PID
getppid() 获取PPID
父进程 与 子进程
PPID始终不变 恒为28528
如果没有更改过shell, 应该是-bash(刚使用Linux大概率没有更改)
shell其实是泛指为所有用户提供操作界面的程序
, 翻译为外壳(与之对应的就是内核)shell可以分为
GUI(图形化界面) shell
和CLI(命令行) shell
而 zsh 和 bash 都属于
CLI shell
,CLI shell
其实就是用户输入指令的界面程序
./AMProcess指令 就是通过 zsh或bash 提供的界面执行的
fork()创建子进程
返回子进程的PID给父进程, 还要返回 0 给子进程
;如果创建失败, 则返回 -1 给父进程, 没有子进程被创建, 并且设置errno(用于异常接收)
#include <iostream>
#include <unistd.h>
using std::cout;
using std::endl;
int main() {
pid_t id = fork(); //直接接收fork()的返回值
cout << "Hello, id = " << id << endl;
return 0;
}
CreatCProcess
可执行程序, 并运行:1. 为什么一个输出语句执行了两次
复制使用了父进程中fork()系统调用之后的所有代码
将子进程添加到了进程的运行队列中
什么是运行队列?
其实系统中所有的进程可以看成排列在一个队列中, 遵循先进先出的原则, 一一执行
Hello, id = 子进程标识符
,Hello, id = 0
, 然后子进程运行结束2. 为什么fork()可以返回两个返回值
当一个函数即将返回一个返回值时 此函数的主体功能是否已经完成了?
fork()即将返回一个返回值时, 其实此进程的子进程已经被创建完成了, 否则根本无法获取并返回子进程的标识符
#include <iostream>
#include <unistd.h>
using std::cout;
using std::endl;
int main() {
pid_t id = fork(); //直接接收fork()的返回值
cout << "Hello, id = " << id << endl;
return 0;
}
#include <iostream>
#include <unistd.h>
using std::cout;
using std::endl;
int main() {
pid_t id = 0;
cout << "Hello, id = " << id << endl;
return 0;
}
Hello, id = 子进程标识符
, 在输出 Hello, id = 0
作者: 哈米d1ch 发表日期:2023 年 3 月 1 日