【Linux】进程二 (PCB & fork/vfork & wait/waitpid & exit/_exit & exec函数族 & 环境变量)

一、描述进程——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()函数之前,子进程与父进程共享进程环境(此时子进程相当于线程),父进程阻塞等待。

三、进程状态&环境变量

 

1、进程状态:

  • 6
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值