[linux操作系统实验]进程的创建(有时程序输出在cmd提示之后?)
问题
- 有的时候,程序运行后的输出结果会在cmd的输出提示之后:
- 本实验中是父进程创建了两个子进程,然后父进程输出 a 后结束,子进程分别输出 b c 后结束。
- 出现该问题其实就在于父进程可能比子进程先结束,此时cmd提示就会冒出来。
- 当我们在命令行里面输入命令并回车执行时,命令内容是交给了shell去执行,而shell是有很多种具体实现的程序:如 bath,zsh ...... 并且正在使用的 shell 是可以修改的。
- 需要查看自己的shell是谁,可以执行cmd命令:echo $SHELL
- cmd就会输出当前使用的shell的位置:
- 原因:我们在shell中运行我们写的实验程序($ ./fork_main)时,shell会等待fork_main这个进程结束,但fork_main里面又创建了两个子进程,shell是不管的,一旦shell启动的父进程fork_main结束,shell的提示(coolight@coolight-Desktop:~$)就会冒出来,而此时子进程才开始输出,因此会出现有些程序输出是在shell提示之后。
实验具体内容
实验内容
编写一段程序,使用系统调用fork( )创建两个子进程。当此程序运行时,在系统中有一个父进程和两个子进程活动。让每一个进程在屏幕上显示一个字符:父进程显示'a',子进程分别显示字符'b'和字符'c'。试观察记录屏幕上的显示结果,并分析原因。
涉及的系统调用
- fork()
- 创建一个新进程。
- 系统调用格式:
- pid=fork( )
- 参数定义:
- int fork( )
- fork( )返回值意义如下:
- 0:在子进程中,pid变量保存的fork( )返回值为0,表示当前进程是子进程。
- >0:在父进程中,pid变量保存的fork( )返回值为子进程的id值(进程唯一标识符)。
- -1:创建失败。
- 如果fork( )调用成功,它向父进程返回子进程的PID,并向子进程返回0,即fork( )被调用了一次,但返回了两次。此时OS在内存中建立一个新进程,所建的新进程是调用fork( )父进程(parent process)的副本,称为子进程(child process)。子进程继承了父进程的许多特性,并具有与父进程完全相同的用户级上下文。父进程与子进程并发执行。
- 核心为fork( )完成以下操作:
- (1)为新进程分配一进程表项和进程标识符,进入fork( )后,核心检查系统是否有足够的资源来建立一个新进程。若资源不足,则fork( )系统调用失败;否则,核心为新进程分配一进程表项和唯一的进程标识符。
- (2)检查同时运行的进程数目,超过预先规定的最大数目时,fork( )系统调用失败。
- (3)拷贝进程表项中的数据,将父进程的当前目录和所有已打开的数据拷贝到子进程表项中,并置进程的状态为“创建”状态。
- (4)子进程继承父进程的所有文件,对父进程当前目录和所有已打开的文件表项中的引用计数加1。
- (5)为子进程创建进程上、下文,进程创建结束,设子进程状态为“内存中就绪”并返回子进程的标识符。
- (6)子进程执行,虽然父进程与子进程程序完全相同,但每个进程都有自己的程序计数器PC(注意子进程的PC开始位置),然后根据pid变量保存的fork( )返回值的不同,执行了不同的分支语句。
- 例:
….. pid=fork( ); if (! pid) printf("I'm the child process!\n"); else if (pid>0) printf("I'm the parent process! \n"); else printf("Fork fail!\n"); …… |
fork( )调用前
….. pid=fork( ); if (! pid) printf("I'm the child process!\n"); else if (pid>0) printf("I'm the parent process!\n "); else printf("Fork fail!\n"); …… | ….. pid=fork( ); if (! pid) printf("I'm the child process!\n"); else if (pid>0) printf("I'm the parent process!\n "); else printf("Fork fail!\n"); …… |
fork( )调用后
源代码
#include <iostream>
#include <unistd.h>
using namespace std;
int main()
{
cout << "<< coolight | [软件202,2006300052,郑泳坤]" << endl;
int fork_num = fork();
if(fork_num == -1){
cout << "<< fork Error" << endl;
}else if(fork_num == 0){ //子进程
fork_num = fork();
if(fork_num == -1){
cout << "<< fork Error" << endl;
}else if(fork_num == 0){ //子进程
sleep(0.5);
cout << "c" << endl;
}else if(fork_num > 0){
sleep(0.5);
cout << "b" << endl;
}
}else if(fork_num > 0){
sleep(0.5);
cout << "a" << endl;
}
return 0;g
}
运行结果截图
思考
- 系统是怎样创建进程的?
- 主要是四个步骤
- 申请空白PCB(过程控制块)
- 为新工序分配资源
- 初始化PCB
- 将新进程插入就绪队列
- 当使用fork()创建时将复制父进程的PCB块,U区和内存图像到新进程。Fork()会用到写时复制,子进程会和父进程共享一些资源,直到有人对一部分数据进行写操作,才会真正开辟空间复制出来这一部分资源
- 主要是四个步骤
- 当首次调用新创建进程时,其入口在哪里?
- 父进程和子进程入口都在fork()函数调用的下一句指令代码。但由于fork()返回值不同,两者可以依据分支语句区分,然后后续执行不同的代码