进程切换,创建,加载,等待与退出

进程切换

进程状态:一个进程的生命周期可以划分为一组状态,这些状态刻画了整个进程。进程状态即体现一个进程的生命状态。

在操作系统中,常见的进程状态是三状态模型,也就是就绪,运行,阻塞(等待),它们的关系如下图:

这里写图片描述

当然,对于一个实际的系统,进程的状态及其转换更为复杂。为此我们引入了新建态和终止态构成了进程的五态模型:

这里写图片描述

关于更详细的进程状态点击此处查看。

在这里,我们聊一聊进程之间的切换。

进程切换,又叫上下文切换,它是指暂停当前运行进程,使其从运行状态变为就绪或者等待状态,同时调度另一个进程从就绪状态变为运行状态

进程切换有如下要求:

这里写图片描述

考虑有如下两个进程P0,P1,开始时候P0处于运行状态,P1出于空闲(等待,就绪),则他们两进程的切换如下图:

这里写图片描述

进程创建

进程创建,基于不同的平台有不同的实现:

Windows进程创建API:CreateProcess(filename)
Linux进程创建系统调用:fork/exec

fork会把一个进程复制成两个进程,其中原先的进程成为父进程(PID不变),产生的新进程成为子进程(分配一个新的PID)。
exec会用新程序来重写当前进程,但是PID不会改变。

关于这两者的区别:

fork函数是用于创建一个子进程,该子进程几乎是父进程的副本,而有时我们希望子进程去执行另外的程序,exec函数族就提供了一个在进程中启动另一个程序执行的方法。它可以根据指定的文件名或目录名找到可执行文件,并用它来取代原调用进程的数据段、代码段和堆栈段,在执行完之后,原调用进程的内容除了进程号外,其他全部被新程序的内容替换了。另外,这里的可执行文件既可以是二进制文件,也可以是Linux下任何可执行脚本文件。

在Linux中使用exec函数族主要有以下两种情况
当进程认为自己不能再为系统和用户做出任何贡献时,就可以调用任何exec 函数族让自己重生。
如果一个进程想执行另一个程序,那么它就可以调用fork函数新建一个进程,然后调用任何一个exec函数使子进程重生。

我们写段代码来说明进程创建这个过程:

这里写图片描述

说明:

当执行完fork这一句后,就产生了两个进程,也就是说,16行代码下是由父子进程共享的,这就是为什么最后结果会分别输出两次this is shared,this is end,因此父子进程各自调用了一次。

那么如何区别父子进程,只有靠进程ID,注意fork函数,它调用的一个奇妙之处就是它仅仅被调用一次,却能够返回两次,它可能有三种不同的返回值:
1)在父进程中,fork返回新创建子进程的进程ID;
2)在子进程中,fork返回0;
3)如果出现错误,fork返回一个负值;

这里写图片描述

当然,fork代价会比较大,因此引入COW技术,也就是延迟拷贝(写时拷贝)

这里写图片描述

进程加载

前面,我们讲了执行fork后,此时生成的子进程是父进程的拷贝,这就意味着代码,数据是一样的,往往这没有什么意义,因此,我们可以加载其他程序到这个进程中执行,注意此时PID依旧不变,但是数据,代码都变化了,具体可看下图:

这里写图片描述

进程等待与退出

等待与退出其实父子进程的一种交互,完成子进程资源的回收

这里写图片描述

这里写图片描述

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<sys/types.h>
#include<sys/wait.h>

extern void print_exit(int status); 

int main()
{
   int pid = fork();
   if (pid < 0)
   {
       printf("fork error\n");
       exit(1);
   }
   else if (pid > 0) //father
   {
       int status = 0;
       int ret = wait(&status);
       printf("father pid = %d, father ppid = %d\n", getpid(), getppid());
       exit_print(status);   
   }
   else //child
   {
       printf("child pid = %d, child ppid = %d\n", getpid(), getppid());
       //exit(123); //正常终止,退出码为123
       //exit(0); //正常终止,退出码为0
       int a = 1/0; //异常终止
       abort();
   }

    return 0;
}
#include<stdio.h>
#include<sys/wait.h>

void exit_print(int status)
{
    if (WIFEXITED(status)) //正常终止
    {
        printf("normally exited, status is %d\n", WEXITSTATUS(status));
    }
    else if (WIFSIGNALED(status)) //异常终止
    {
        printf("abnormally exited, signal is %d\n", WTERMSIG(status));
    }
    else if (WIFSTOPPED(status)) //进程暂停
    {
        printf("child stopped, signal is %d\n", WSTOPSIG(status));
    }

}

其他

这里写图片描述

这里写图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值