一、进程的理解
首先我们知道我们的操作其实都是在运行程序,不仅是在windows上打开软件还是在Linux上执行指令,而程序存在于磁盘上,程序的要想运行就要把程序的代码和数据从磁盘加载到内存,那么到这一步是创建了一个进程吗?其实不是,实际上在程序运行起来后,CPU还会创建一个PCB(process control block)进程控制块,描述一个进程的结构体。此时才算是一个进程被创建。
所以我们得到了一个关键信息:进程 = PCB + 代码 + 数据
所以现在操作系统就进程的控制就变成了对链表(内核数据结构)的增删查改。
二、Linux中的进程
PCB是对进程的总称,在Linux中是struct task_struct
所以调度进程本质就是让进程控制块进行排队。
进程 = 内核task_struct + 代码 + 数据
进程的动态运行:task_struct在不同队列中访问不同资源。
三、task_struct的内部属性
1、启动进程
(1)./xxx
让系统创建进程并执行。
自己写的代码的可执行程序 == 系统命令 == 可执行文件
(2)pid
每一行进程都有自己的标识符pid
指令 ps ajx head -1 && ps ajx | grep 文件名 可以查看进程与头部信息
(3)显示pid
一个进程想知道自己的pid一般是不能从指令中直接拿到的,因为操作者不能越过操作系统来对底层进行访问。所以我们要使用系统给我们的接口,也就是系统调用来查看。
头文件 #include<sys/types.h> #include<unistd.h>
函数 getpid()
(4)程序的终止与消除
ctrl c:终止程序
kill -9 pid:杀掉程序
2、进程的创建
(1)为什么我们要创建子进程?
因为我们想让子进程执行与父进程不一样的代码。
(2)父进程的ppid要通过 getppid() 函数获得。
(3)如何创建子进程?
用fork()函数可以创建子进程。
注意到fork()函数返回值是pid_t,其实fork()会有两个返回值,一个等于0代表子进程,一个返回子进程的pid大于0,是父进程,若返回值小于0,那就是出现错误。
那为什么fork()函数会有两个返回值呢?
其实在fork()内部已经有父子进程,分别返回两个值。
(4)task_ struct内容分类
标示符: 描述本进程的唯一标示符,用来区别其他进程。
状态: 任务状态,退出代码,退出信号等。
优先级: 相对于其他进程的优先级。
程序计数器: 程序中即将被执行的下一条指令的地址。
内存指针: 包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针
上下文数据: 进程执行时处理器的寄存器中的数据。
I/O状态信息: 包括显示的I/O请求,分配给进程的I/O设备和被进程使用的文件列表。
记账信息: 可能包括处理器时间总和,使用的时钟数总和,时间限制,记账号等。
其他信息
(5)组织进程
可以在内核源代码里找到它。所有运行在系统里的进程都以task_struct链表的形式存在内核里。