[ linux-系统 ] 进程概念与基本操作
1.进程的概念
1. 什么是进程?
进程是一个运行中的程序。当可执行文件被加载到内存中时,该程序就成为了一个进程。
2. 多进程管理
操作系统中可能同时存在大量的进程吗?当然可以
操作系统需要管理这些进程,以确保系统资源(如CPU时间、内存等)合理分配。管理进程的本质是对进程数据的管理。
我们需要 先描述再组织。
所以,当一个程序加载到内存时,操作系统做的不仅仅只是把代码和数据加入到内存,
还要管理进程,创建对应的数据结构。
Linux 操作系统的内核是 C 语言写的,描述时就用到struct
2.描述进程--PCB
在操作系统中,用于描述进程的结构体称为进程控制块PCB(process control block)。在Linux中,这种结构体称为 task_struct
。
task_struct
的结构
struct task_struct {volatile long state;void *stack;atomic_t usage;unsigned int flags; unsigned int ptrace;unsigned long ptrace_message;siginfo_t *last_siginfo; int lock_depth; // ... 其他属性
};
task_struct
包含进程的所有属性数据,如进程状态、优先级、程序计数器、内存指针、上下文数据、I/O状态信息和记账信息等。
操作系统对进程的管理,最终变成了对链表的增删查改。
什么是进程?目前为止我们可以总结成:进程 = 可执行程序 + 该进程对应的内核数据结构
操作系统不相信任何人的,不会直接暴露自己的任何数据结构,代码逻辑,其他数据相关的细节。
想做系统是通过 系统调用 的方式,对外提供接口服务的。
下面我们将来学习一些系统接口
3. 进程查看与管理
1.使用指令查看进程
先创建一个死循环进行测试
在另一个终端输入以下指令,可以看到进行中的程序./myproc
按ctrl + c结束程序,再输入指令发现进程也结束了,看不到./myproc
通过指令如 ps
和 top
可以查看系统中的进程信息。例如,使用 ps aux
可以显示系统中所有的进程
若需查看特定进程,可以使用 grep
过滤:
2.通过系统调用获取进程标示符
系统调用getpid(),返回当前进程ID
杀掉一个进程还可以用kill命令 kill -9 + 进程ID
/proc 查看进程信息
在 Linux 系统中,/proc
是一个非常重要的伪文件系统(内存级别),不是磁盘文件,也被叫做 “进程文件系统”。它的作用是提供内核数据结构的接口,让用户可以通过文件的形式访问系统进程和内核的信息,而不需要直接与内核进行交互
如下图,我们运行myproc.c,在proc目录里就创建了一个文件夹,名字就是./myproc的进程ID
文件夹里记录这myproc的所有进程信息
在 Linux 系统中,当这个程序已经运行起来的时候,删掉可执行程序,依然可以继续运行,因为已经被加载到内存中
exe:通过这个链接,能够确定进程当前运行的是哪个程序。(指出进程对应的可执行程序的磁盘文件)
cwd: 当前工作目录(指出进程当前的工作路径)
理解CWD(理解当前路径)
CWD
(Current Working Directory)是一个指向进程当前工作目录的符号链接。通过该链接可以确定进程当前正在操作的目录路径。
看以下代码,我们在学习C语言时,文件创建fopen后面如果不带路径,就在默认路径下创建
所谓的当前路径是什么呢?其实是当前进程所在的路径(CWD)
进程会自己维护,进程会知道自己的工作路径在哪里
可以通过chdir改变当前工作路径
3.ppid
在linux系统中,启动之后,新创建任何进程的时候,都是由自己的父进程创建的!
系统调用getppid获取父进程,发现ppid不变,我们的程序myproc是由-bash创建的
bash是Linux系统中最常用的命令行解释器(shell)所以我们在命令行中创建的进程都是bash做的(命令行中,执行程序/命令,本质是bash的进程,创建子进程,由子进程执行我们的代码)
4.使用系统调用,创建进程
fork创建子进程
运行以下代码,发现fork()之后,printf打印了两次
说明有两个执行流,父进程和子进程
执行以下代码,看fork函数的返回值:
- 返回值决定当前执行环境:
- 子进程:返回
0
- 父进程:返回子进程的 PID(正整数)
- 失败:返回
-1
(如内存不足或进程数达到上限)
- 子进程:返回
上面代码if和else if 为什么会同时成立?
原因:fork()的
机制
fork() -> 两个进程 -> 父子关系 -> 一般而言,代码父子共享,但是数据各自私有一份
我们的程序myproc.c第一次从磁盘加载到内存,操作系统为它创建PCB , 当代码执行到fork()时,
为什么代码共享?因为子进程并没有二次加载
新创建进程,操作系统也要为它创建PCB,父进程和子进程的区别在于父进程从磁盘中加载代码和数据,新创建的子进程并没有从磁盘中加载代码和数据,而进程=内核数据结构+代码和数据,子进程只有内核数据结构,子进程从父进程中加载代码和数据,子进程和父进程共享一份代码
验证数据各自私有
先看以下代码对于同一份全局变量,父进程只读不做修改,子进程做修改,观察结果
父进程的gval=0,子进程的gval不断变化
说明:进程具有很强的独立性,多个进程之间,运行时,互不影响,即便是父子进程
返回的本质,就是向指定变量进行写入返回值数据
打印的本质,就是读取