一、PCB进程控制块
1、基本概念
进程信息被放在一个叫做进程控制块的数据结构中,可以理解为进程属性的集合,这个集合被称之为PCB,在Linux系统下PCB是task_struct。
(1)task_struct是用于描述进程的结构体,他会被装载到RAM(内存)中,并且包含着进程的信息。
(2)进程=可执行程序+内核数据结构(PCB),PCB方便OS对进程进行管理。
2、task_ struct内容分类
(1)标示符: 描述本进程的唯一标示符,用来区别其他进程。
(2)状态: 任务状态,退出代码,退出信号等。
(3)优先级: 相对于其他进程的优先级。
(4)程序计数器: 程序中即将被执行的下一条指令的地址。
(5)内存指针: 包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针
(6)上下文数据: 进程执行时处理器的寄存器中的数据[休学例子,要加图CPU,寄存器]。
(7)I/O状态信息: 包括显示的I/O请求,分配给进程的I/O设备和被进程使用的文件列表。
(8)记账信息: 可能包括处理器时间总和,使用的时钟数总和,时间限制,记账号等。
(9)其他信息
3、进程PCB有状态概念
PCB可以根据不同状态有不同的反应。一旦被调度,调度的代码一行行跑,以PCB为代表的进程有了动态的属性,动态属性就是指现在或者将来会被CPU执行
二、查看进程
1、指令:ps-ajx
①第二条指令可以直接提取出第一行
②在查看进程的时候要过滤一部分内容,因为grep也会形成一个进程,需要提取出需要的进程。我们之前运行的所有指令、软件、自己写的程序,都是进程
2、指令:ls /proc
proc是进程的简称,这里会维护一个动态的目录结构,目录的名称就是以这个进程的pid命名的。
三、进程标识符
1、进程id(PID)
(1)id用来标识一个进程,可以通过进程PID对进程进行管理
(2)kill -9+进程id,可以干掉一个进程
2、父进程(PPID)
(1)在命令行中,父进程一般是命令行解释器、Linux每次登陆之后,命令行启动进程之后,父进程不变。
(2)父进程是bash,我们命令行启动的进程都是bash的子进程
二、进程的创建
(一)fork函数
1.基本概念
fork
函数是操作系统中的一个系统调用,用于创建一个新的进程,该进程是调用fork函数的进程的一个副本。新创建的进程称为子进程,原始进程称为父进程。
函数原型
#include <unistd.h>
pid_t fork(void);
2、fort的返回值
(1)父进程的返回值
- 如果
fork
函数返回一个大于0的值,表示当前执行的是父进程。这个返回值是子进程的PID(进程ID),可以用来操作子进程。 - 如果
fork
函数返回-1,表示创建子进程失败,通常是因为系统资源不足或权限不够等原因,此时应该处理错误情况。
(2)子进程的返回值
- 如果
fork
函数返回0,表示当前执行的是子进程。可以根据需要在子进程中执行相应的任务逻辑。
根据fork函数的返回值,可以在程序中使用条件语句来区分父进程和子进程的不同逻辑,从而实现不同的处理方式。例如,可以在父进程中等待子进程的完成,或者在子进程中执行某种特定的任务。
3、fork函数的写时拷贝
(1)用途
fork
函数的写时拷贝(Copy-on-Write,COW)是一种优化策略,用于在创建子进程时避免立即复制父进程的整个地址空间,这种机制可以提高性能和减少内存消耗。
(2)fork函数创建子进程的步骤
·父进程会创建一个与自己拥有相同地址空间的子进程。
·子进程继承了父进程的页表,这意味着它与父进程共享相同的虚拟内存地址空间。
·在初始阶段,父进程和子进程共享所有的物理页面,这些页面被标记为“只读”。
·当父进程或子进程尝试修改共享的内存页时,操作系统会将相应的页面复制到一个新的物理页面,并将其标记为“可写”。
·父进程和子进程现在各自拥有一个独立的物理页面,它们不再共享相同的数据。
通过写时拷贝技术,父进程和子进程共享大部分内存页,只在需要修改共享内存时才进行复制操作。这样可以节省时间和内存,并提高系统性能。例如,在fork之后,如果子进程立即执行exec函数加载了一个新的程序,那么就不需要进行任何复制操作,这是因为子进程并不需要修改父进程的内存数据。
需要注意的是,写时拷贝只是在逻辑上实现了共享,而不是物理上的共享。父进程和子进程仍然拥有各自独立的虚拟地址空间,它们之间的共享是通过允许读取相同的物理内存来实现的,只有在修改时才会发生内存复制。