一、描述进程——PCB
·进程信息被放在一个叫做进程控制块的数据结构中,可以理解为进程属性的集合
·我们称为PCB,Linux操作系统下的PCB是:task struct
2、task_struct——PCB的一种
·在Linux中描述进程的结构体叫做task_struct.
·task_struct是Linux内核的一种数据结构,它会被装载到RAM(内存)里包含着进程的信息
3.task_struct内容分类
·标示符:描述本进程的唯一标示符,用来区别其他进程
·状态:任务状态,退出代码,退出信号
·优先级:相对于其他进程的优先级
·程序计数器:程序中即将被执行的下一条指令的地址
·内存指针:包括程序代码和进程相关的指针,还有和其他进程共享的指针
·上下文数据:进程执行时处理器的寄存器中的数据
·I/O状态信息:包括显示的I/O请求,分配给进程的I/O设备和被进程使用的文件列表
·记账信息:可能包括处理器时间总和,使用的时钟数总和,时间限制,记账号等
给张图方便理解:
二、进程创建(fork&vfork)
在Linux系统内,创建子进程的方法是使用系统调用fork()函数。fork()函数是Linux系统内一个非常重要的函数,它与我们之前学过的函数有一个显著的区别:fork()函数调用一次却会得到两个返回值。
fork()函数
所需头文件:#include<stdio.h>
#include<unistd.h>
函数原型: pid_t fork()
函数返回值:
== 0 子进程
>0 父进程,返回值为创建出的子进程的PID
<0 出错
fork()函数用于从一个已经存在的进程内创建一个新的进程,新的进程称为“子进程”,相应地称创建子进程的进程为“父进程”。使用fork()函数得到的子进程是父进程的复制品,子进程完全复制了父进程的资源,包括进程上下文、代码区、数据区、堆区、栈区、内存信息、打开文件的文件描述符、信号处理函数、进程优先级、进程组号、当前工作目录、根目录、资源限制和控制终端等信息,而子进程与父进程的区别有进程号、资源使用情况和计时器等。
练习:创建一个子进程,打印父子进程的pid
#include<stdio.h>
#include<sys/types.h>
#include<unistd.h>
int main()
{
printf("linux66\n");
pid_t ret = fork();
if(ret < 0)
{
perror("失败");
return 0;
}
else if(ret == 0 )
{
//child
printf("i am child :[%d] - [%d] \n", getpid(),getppid());
}
else
{
printf("i am father :[%d] - [%d] \n", getpid(),getppid());
}
return 0 ;
}
在使用fork()函数创建子进程的时候,要有一个概念:在调用fork()函数前是一个进程在执行这段代码,而调用fork()函数后就变成了两个进程在执行这段代码。两个进程所执行的代码完全相同,都会执行接下来的if-else判断语句块。
当子进程从父进程内复制后,父进程与子进程内都有一个"pid"变量:在父进程中,fork()函数会将子进程的PID返回给父进程,即父进程的pid变量内存储的是一个大于0的整数;而在子进程中,fork()函数会返回0,即子进程的pid变量内存储的是0;如果创建进程出现错误,则会返回-1,不会创建子进程。
fork()函数一般不会返回错误,若fork()函数返回错误,则可能是当前系统内进程已经达到上限,或者内存不足。
注意:父子进程的运行先后顺序是完全随机的(抢占式执行),也就是说在使用fork()函数的默认情况下,无法控制父进程在子进程前进行还是子进程在父进程前进行。
vfork()函数
所需头文件:#include<stdio.h>
#include<unistd.h>
函数原型:pid_t vfork()
返回值:
== 0 子进程
>0 父进程,返回值为创建出的子进程的PID
<0 出错
vfork()函数功能与fork()函数功能类似不过更加彻底:内核不再给子进程创建虚拟空间,直接让子进程共享父进程的虚拟空间。当父子进程中有更改相应段的行为发生时,再为子进程相应的段创建虚拟空间并分配物理空间。在vfork()函数创建子进程后父进程会阻塞,保证子进程先行运行。
vfork()函数创建的子进程会与父进程(在调用exec函数族函数或exit()函数前)共用地址空间,此时子进程如果使用变量则会直接修改父进程的变量值。因此,vfork()函数创建的子进程可能会对父进程产生干扰。另外,如果子进程未调用exec函数族函数或exit()函数,则父子进程会出现死锁现象。
fork()函数与vfork()函数的主要区别如下:
1.vfork()函数保证子进程先行运行,在子进程调度exec函数族函数或者exit()函数后父进程才会被调度运行。如果子进程需要依赖父进程的进一步动作,则会产生死锁
2.fork()函数需要拷贝父进程的进程环境,而vfork()函数则不需要完全拷贝父进程的进程环境,在子进程调用exec函数族函数或者exit()函数之前,子进程与父进程共享进程环境(此时子进程相当于线程),父进程阻塞等待。