目录
一、什么是进程
1.课本概念
进程是程序的一个执行实例,是操作系统对程序执行的基本单位
从不同角度,可以有不同的定义:
- 进程是程序的一次执行过程
- 进程是一个程序及其数据在处理机上顺序执行时所发生的活动
- 进程是系统进行资源分配和调度的一个独立单位
2.内核观点
担当分配系统资源(CPU时间、内存)的实体
二、进程的描述-PCB
1.什么是PCB
- 进程控制块(PCB)是操作系统为了管理和维护进程而设置的一个专门的数据结构。
- 作用:PCB使一个在多道程序环境下不能独立运行的程序(含数据)成为一个能独立运行的基本单位,或与其他进程并发执行的进程。通过PCB,操作系统可以跟踪和控制每个进程的运行,并在需要时恢复进程的执行。
2.PCB的组织方式
- 线性表方式:将所有的PCB连续地存放在内存的系统区,适用于系统中进程数目不多的情况
- 索引表方式:系统按照进程的状态分别建立就绪索引表、阻塞索引表等,提高了查找特定PCB的效率
- 链接表方式:系统按照进程的状态将进程的PCB组成队列,形成就绪队列、阻塞队列、运行队列等,具有灵活性高的优点,但查找特定PCB的效率较低
- 数组方式:使用一个固定大小的数组来存储所有的PCB,通过索引来访问和操作PCB,提高了查找PCB的效率,但需要预先分配固定大小的数组空间
- 树形结构方式:使用树的数据结构来管理PCB,每个PCB都作为一个节点,节点之间通过父子关系连接起来,可以灵活地组织PCB并提供更多的进程管理功能,但增加了复杂性
3.task_struct是Linux操作系统下的PCB
- task_struct是Linux内核中的一种数据结构,它会被装载到RAM(内存)中并包含着进程信息
4.task_struct内容分类
task_struct结构体内部包含多个元素
- 标示符: 描述本进程的唯一标示符,用来区别其他进程
- 状态: 任务状态,退出代码,退出信号等
- 优先级: 相对于其他进程的优先级
- 程序计数器: 程序中即将被执行的下一条指令的地址
- 内存指针: 包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针
- 上下文数据: 进程执行时处理器的寄存器中的数据[休学例子,要加图CPU,寄存器]
- I/O状态信息: 包括显示的I/O请求,分配给进程的I/O设备和被进程使用的文件列表
- 记账信息: 可能包括处理器时间总和,使用的时钟数总和,时间限制,记账号等
- 其他信息
三、进程的查看
进程信息可以通过系统文件夹查看
这里只做简单介绍,细节内容后续说明
正在执行的进程的信息可以使用 指令查看
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
while(1)
{
printf("1");
sleep(1);
}
return 0;
}
四、进程的创建
1.查看子进程id和父进程id
- getpid()函数和getppid()函数
演示实例1:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int main()
{
printf("pid:%d\n",getpid());
printf("ppid:%d\n",getppid());
return 0;
}
2.fork初识
fork()
是一个用于创建新进程的系统调用。当调用fork()
时,它会创建一个与当前进程(称为父进程)几乎完全相同的子进程。新创建的子进程会从fork()
系统调用的返回点开始执行,并且它拥有父进程的环境、打开的文件描述符、内存空间(但有自己的地址空间副本,采用写时复制机制)等。
演示实例1:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int main()
{
pid_t ret = fork();
printf("pid:%d ret:%d\n",getpid(),ret);
return 0;
}
- 这里可以看到原本一行的代码却输出了两行结果,这是为什么?
- 这是由于fork()函数创建了一个子进程,打印结果第一行是父进程的pid和fork()返回值,第二行是子进程的pid和fork()返回值
演示实例2:
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>
int main()
{
pid_t ret = fork();
if(ret < 0)
{
perror("fork");
return 1;
}
else if(ret == 0)
{
printf("我是子进程,我的pid是%d\n",getpid());
}
else
{
printf("我是父进程,我的pid是%d\n",getpid());
}
return 0;
}
- 这里可以看到,根据fork()返回值的不同,会进入到不同的if语句中,从而再次印证fork()函数创建了不同于原来进程的新进程