进程的基本概念
1.冯诺依曼体系结构
我们常见的计算机大都遵循冯诺依曼体系结构
我们所认识的计算机,都是由一个一个硬件组成的
输入单元:键盘,鼠标等等
CPU
输出单元:显示器。打印机,音箱等等
关于冯诺依曼架构的特点:
储存器指的是内存
CPU只能对内存进行读写,不能访问外设
外设要输入或输出数据,也只能写入内存或从内存中读写
数据要在计算机结构进行传输,从一个设备到另一个设备,本质上是数据的拷贝,设备之间的拷贝效率决定了计算机的整体效率,当我们运算数据时,CPU直接从储存器读取数据,减少了数据从输入设备到CPU的传输时间,如果没有了储存器,直接从输入设备直接把数据传给CPU,那么CPU的运算效率远远大于输入设备的传输效率,这样计算机的整体效率就取决与数据传输的效率,就很慢了,所以这就是冯诺依曼的优秀之处
2.操作系统
概念:任何计算机都包含一个基本的程序集合,称为操作系统(OS),操作系统包括
内核(进程管理,内存管理,文件管理,驱动管理)
其他程序(例如函数库,shell库)
操作系统是管理硬件之间数据传输的软件
3.进程
1.进程的概念
什么是进程?
进程就是PCB+代码和数据
当我们要执行一个可执行文件时,会先把可执行文件从磁盘中拷贝到内存中,然后对应生成一个pcb结构体,也叫做进程控制块,然后cpu通过管理pcb的属性,对可执行文件进行管理,一个进程一定有对应的pcb,
操作系统要对进程先描述,再组织,描述就是用pcb描述进程的属性,然后把pcb组织起来管理,操作系统中可以同时存在很多进程,然后多个pcb结构体组成链表数据结构或者其他数据结构方便管理,所以对进程的管理就变成了对链表的管理,
进程=pcb+代码和数据,在linux操作系统中,pcb对应的具体名字叫做task_struct(进程控制块),
如何理解进程动态运行?
只要task_struct在不同的队列中就可以访问不同的资源,
2.进程的task_struct属性
1.启动进程
./xxx(可执行文件),本质上是让系统创建进程并运行,
在linux运行的大部分指令,本质上都是一个进程,例如:ll pwd touhc file
2.进程pid
每个进程都有自己的唯一标识符,叫做进程pid,
用ps axj命令可以查看所有正在运行的进程,ps axj | head -1可以只显示第一行,显示对应的目录,用&&可以两条指令一起执行,ps axj | grep process 可以找到我们需要看的进程,所以我们可以这样写
ps axj |head -1&& ps axj |grep process
每个进程都有唯一的pid,如果我们想自己获得对应进程的pid该怎么写?
3.getpid()
获得对应的进程pid,可以调用对应的getpid()函数
getpid的返回值是pid_t,实际就是封装的无符号整形,
kill -9 getpid可以结束进程
4.进程创建的代码方式
进程分为子进程和父进程,分别有对应的pid和ppid,getppid可以获得父进程pid,一个父进程可以构造出很多个子进程,父进程的代码和数据是从磁盘中加载到内存中的,而子进程的代码是直接拷贝的父进程的,进程都是独立的,
#include <stdio.h>
18 #include <unistd.h>
19 #include <sys/types.h>
20
21 int main() {
22 pid_t pid = fork();
23
24 if (pid < 0) {
25 // fork失败
26 perror("fork failed");
27 return 1;
28 } else if (pid == 0) {
29 // 子进程
30 printf("I am the child process PID %d PPID %d\n", getpid(), getppid());
31 } else {
32 // 父进程
33 printf("I am the parent process PID %d PPID is %d\n", getpid(), pid);
34 }
35 return 0;
36 }
fork函数包含在usistd.h,sys/types.h中,fork函数可以用来创建一个新进程,成为子进程,它是调用父进程的副本,如果fork返回-1,也就是小于0的数,就是创建进程失败,如果返回0,则创建的是子进程,如果返回值大于0,那么创建的是父进程,
3.进程的状态
一个进程可以有几种状态,比如:
R(running)表示运行状态,并不意味着进程在运行状态,他表示进程要么在运行,要么在运行队列中
S(sleeping)表示睡眠状态,意味着进程在等待事件完成
D(Disk sleep),是linux系统特有的一种状态,也叫不可中断状态,这个状态的进程通常在等待IO的结束,
T/t(stopped)表示停止状态,比如我们运行一个程序,在断点处暂停,那么这个进程就是T/t状态,
z(zombie)表示僵尸进程,一个进程已经运行完毕,但是要维持自己的退出信息,在自己的task_struct 中会记录退出信息,等父进程来读取,如果父进程没有读取,那么这个进程就一直存在,成为僵尸进程,
父进程读取子进程的退出信息要调用wati()或waitpid()函数
当一个进程结束时,会记录自己的退出信息在task_struct中,然后释放代码和数据,而退出信息需要等到父进程读取后,才会释放,所以僵尸进程存在会造成内存泄漏,
我们直接在命令行里启动的进程,他的父进程是bash,bash会自动回收结束的进程, 所以不会产生僵尸进程,
4.孤儿进程
父进程如果先退出,其子进程还在运行,那么子进程就变成了孤儿进程,孤儿进程通常由操作系统接管
孤儿进程导致的一些问题:
1.资源占用,如果孤儿进程没有被适当地终止,它们可能会继续占用系统资源,如内存和CPU时间。
2.数据不一致,如果孤儿进程负责某些数据的更新或维护,那么在父进程终止后,这些数据可能会处于不一致的状态。
3.错误处理,孤儿进程可能无法正确处理错误,因为它们无法将错误信息传递给父进程。
5.进程的阻塞,挂起和运行
运行态
当cpu要运行一系列的进程时,他不会一个进程一直运行到结束,而是调度运行,cpu中有一个运行队列
cpu运行进程的方法是通过是通过调度算法管理的
当进程在运行中或者运行队列中都是R状态的
比如说cpu可以基于时间片进行轮转调度的,让多个进程以切换的方式进行调度,在一个时间段中同时推进进程,叫做并发,
在同一时刻都有多个进程在运行,叫做并行
进程在切换时,cpu中的寄存器,会保存进程的上下文数据,
阻塞态
阻塞态也称为等待态,指进程因等待某些事件(如输入/输出操作、信号量、锁等)而暂停运行
特点:
阻塞态无法被调度运行,因为他们在等待某个外部事件
挂起态
挂起态是指进程因为某些原因被操作系统暂时停止执行状态,在这种状态下,进程的所有活动被暂停,
进程的数据和代码会被保存到磁盘的swaps分区,从而为内存留出空间,这样减轻了内存的压力,但是降低了效率,使用效率换空间。