目录
1.什么是进程
进程是一个执行的实例,即正在被执行的程序。
我们可以打开win下的进程管理器,里面的内容给就是一个个的进程。
由于可能存在大量的进程,操作系统需要对进程来进行管理,管理的方式就是:先描述,再组织。
2.Linux系统下查看进程
(1)ps axjlgrep 进程名
要观察进程,那么这个进程一定是在一个执行的条件下才能进行观察,因此我们可以写一个死循环的程序,使它一直在运行:
#include <stdio.h>
2 int main()
3 {
4 while(1)
5 {
6 printf("hello process!\n");
E> 7 sleep(1);
8 }
9 return 0;
10 }
我们来运行一下这个程序,要观察进程还需要再开出一个窗口来输入命令,查看进程。
ps ajx|head -1 && ps axj |grep "mytest"
使用该命令我们就可以查看当前的进程了
这一行显示的就是当前进程的各种属性,当然这并不完全是。上面一行就是属性的名称(也就是要写入task_struct中的内容),至于下面一行,由于grep指令也会创建一个进程,所有我们可以先不用考虑它。
如果我们将程序Ctrl C结束掉,此时再查看进程,我们发现该进程已经没有了
(2)/proc查看
我们还可以在proc系统文件中通过查找进程码来进行进程查看,此时即显示该进程的信息,其中exe表示的是当前正在执行谁,cwd表示的是当前工作目录,其实这也就是为什么我们使用C语言进行创建文件,默认路径就是当前路径的原因,他会通过cwd读取当前路径再创建文件。
3.PCB
从上一节中,我们了解操作系统的管理方式是:先描述,再组织。其中先描述指的是将信息存入结构体中,再组织指的是将这些
结构体以一定的数据结构进行连接起来。
放到进程上来说,其中存放进程信息的结构体叫做:进程控制块,简称PCB(process control blog),
PCB就是操作系统对进程的先描述的体现。
注意,PCB是一个总称,在Linux系统下的PCB是一个名为task_struct的结构体(Linux是使用C语言写的)。也就是说在Linux系统下,每创建一个进程就会建立一个task_struct结构体来存储该进程的基本信息。
4.进程和程序之间的关系
我们所说的程序通常是指可执行程序,它本质上就是一个文件,当我们要运行这个程序的时候,我们会将其加载到内存中:
在加载到内存中后,操作系统会为该程序建立一个PCB来存储该程序中的信息,PCB与程序的总体就称为进程。
进程=程序文件内容+与进程相关的数据结构(PCB)
即用红色部分圈起来的整体。
操作系统对进程的管理不是直接对程序文件进行操作,而是通过PCB(管理者与被管理者不接触的原则)进行管理,因此PCB中一定存在找到该程序文件的信息,程序文件包括程序代码和数据。
在内存中不可能只存在一个进程,不同进程的PCB操作系统使用一定的数据结构连接起来,这就是再组织的过程,注意连接的是PCB而不是文件。
5.LInux下(PCB)task_struct中的内容
(1)PID和PPID
PID表示的是当前进程的编号,PPID表示的是当前的父进程的编号。
我们可以使用getpid()和getppid()两个函数来打印当前进程的编号,还拿之前的代码据举例:
#include<stdio.h>
#include<unistd.h>
int main()
{
while(1)
{
printf("pid:%d ppid:%d\n",getpid(),getppid());
sleep(2);
}
return 0;
}
然后运行这个程序,我们可以观察它的进程和父进程的编号:
分别是19970和10569,那么它的父进程到底是谁呢?
我们可以在另一个界面查看一下:
我们发现父进程就是bash。同时我们还需要知道一个结论。
在命令行执行的命令其实也是进程,他们的父进程都是bash。
(2)状态
状态包括:任务状态,退出码,退出信号等。
这里只对退出码来进行说明,后面说
我们在写C语言和C++程序的时候,最后是不是都要有一个返回值呢?在大部分情况下,返回值是0,即return 0,其实这个0就是该程序的退出码。、
如果让我们的程序返回100呢?那么这个程序的退出码就是100。
int main()
{
return 100;
}
我们可以通过:
echo $
指令来查看程序退出码:
该命令查看的退出码是离该命令最近的进程的退出码。
(3)优先级
CPU的资源是有限的,而进程有多个,这就存在谁先使用CPU谁后使用CPU的问题。
优先级指的是该进程相对于其他进程的优先级。然后通过优先级队列来按顺序使用CPU资源。注意优先级队列的元素不是程序而是程序的PCB(具体到Lintask_struct)。通过PCB可以找到该程序。
即不同进程执行的顺序,注意优先级决定的先后问题,而之前所说的权限指的是能与不能的问题。
(4)程序计算器
程序中即将被执行的下一条指令的地址。
当程序文件被加载到CPU中之后,程序需要被一条一条的执行,CPU有一个pc寄存器,其中存放的就是下一条指令的地址.
从而使得程序可以一步一步正常运行下去,它也显示在我们的PCB中.
(5)内存指针
可以理解为,根据PCB中的内存指针可以帮助我们找到程序的代码和数据,即程序文件在内存的位置.
(6)I/O状态信息
进程可能会对外存进行操作,比如一个C语言程序进行文件的读写,I/O状态信息存入的就是该进程可以访问的外部设备的信息.
(7)记账信息
记账信息,及该进程处理时间总和,使用的时钟数总和,时间限制,记帐号等等.从而保证各个进程公平地分配CPU的资源.
(8)上下文数据
我们知道,进程在由CPU执行的时候是按一定顺序的,由优先级队列来控制执行的顺序.
在CPU中有一组存放临时数据的存储单元,我们称之为寄存器,当进程加载到CPU中之后,寄存器会保证正在运行的程序的临时数据.
有了寄存器的概念,下面我们讨论上下文数据这一个概念:
我们发现,虽然有优先级队列来规定进程的执行顺序,但是在我们自己的电脑中,为什么可以同时运行多个进程呢?
其本质是通过CPU的快速切换完成的.
这才是操作系统控制CPU处理进程的方式,让第一个进程(对应PCB1)在CPU中运行一段时间(并没有运行结束),然后将其放在优先级队列的队尾,然后CPU处理第二个进程,处理一段时间后(没执行完),将第二个进程再放到队尾,依次类推.
其中处理的一段时间,我们称之为:时间片.时间片通常很短,因此我们感觉的就是多个进程在同时执行.
那么问题出现了,当进程1在CPU中每一次执行之后是会产生临时数据的,存放在寄存器中,之后进程2占用CPU,此时由于寄存器只有一套,那么进程 2产生的临时数据就会对寄存器中的内容进行刷新.当进程1再来占用CPU的时候之前产生的临时数据没了?那怎么确定进程1执行到哪里了呢?
此时才引出了我们的主角:上下文数据.它会保存进程每一次在CPU执行之后得到的临时数据,存放在PCB中,当又一次轮到该进程使用CPU的时候,上下文数据会直接导入寄存器中,从而控制进程的执行进度.
同时,通过上下文数据,我们也可以感受到进程是被切换的.