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

来源:互联网 发布:医院设备科工资知乎 编辑:程序博客网 时间:2024/06/01 08:20

进程切换

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

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

这里写图片描述

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

这里写图片描述

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

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

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

进程切换有如下要求:

这里写图片描述

考虑有如下两个进程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
原创粉丝点击