当前位置:文档之家› 实验一进程创建 Linux实验报告

实验一进程创建 Linux实验报告

实验一进程创建
【实验目的和要求】
1、1.了解进程的概念及意义;
2.了解子进程和父进程;
3.掌握创建进程的方法。

【实验内容】
1、1.子进程和父进程的创建;
2.编写附件中的程序实例;
3.撰写实验报告。

【实验原理】
1、原型:
#include <unistd.h>
pid_t fork(void);
在linux中fork函数时非常重要的函数,它从已存在进程中创建一个新进程。

新进程为子进程,而原进程为父进程。

fork函数创建子进程的过程为:使用fork函数得到的子进程是父进程的一个复制品,它从父进程继承了进程的地址空间,包括进程上下文、进程堆栈、内存信息、打开的文件描述符、信号控制设定、进程优先级、进程组号、当前工作目录、根目录、资源限制、控制终端,而子进程所独有的只有它的进程号、资源使用和计时器等。

通过这种复制方式创建出子进程后,原有进程和子进程都从函数fork返回,各自继续往下运行,但是原进程的fork返回值与子进程的fork返回值不同,在原进程中,fork返回子进程的pid,而在子进程中,fork返回0,如果fork返回负值,表示创建子进程失败。

子进程和父进程继续执行fork调用之后的指令。

子进程是父进程的副本。

例如,子进程获得父进程数据空间、堆和栈的副本。

注意,这是子进程所有用的副本。

父进程和子进程并不共享这些存储空间部分。

父进程和子进程共享正文段。

2、原型:
#include <unistd.h>
pid_t vfork(void);
vfork函数的调用序列和返回值与fork相同,但两者的语义不同。

vfork函数用于创建一个新进程,而该进程的目的是exec一个新程序。

vfork不将父进程的地址空间完全复制到子进程中,因为子进程会立即调用exec,它在父进程的空间中运行。

vfork保证子进程先运行,在它调用exit之后父进程才可能被调度运行,当子进程调用这两个函数中的任意一个时,父进程会恢复运行。

【程序代码】
1、1_fork.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int var = 10;
int main(int argc,char *argv[])
{
pid_t pid;
int num = 9;
pid = fork();
if(pid<0)//fork函数创建进程失败!
{
perror("fork");
}
if(pid==0)//子进程
{
var++;
num++;
printf("in son process var = %d,num=%d\n",var,num); }
else//父进程
{
sleep(1);
printf("in father process var=%d,num=%d\n",var,num); }
printf("common code area\n");
return 0;
}
2、2_vfork.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int var = 10;
int main(int argc,char *argv[])
{
pid_t pid;
int num = 9;
pid = vfork();//创建进程
if(pid<0)
{
perror("vfork");
}
if(pid == 0)
{
var++;
num++;
printf("in son process var=%d,num=%d\n",var,num);
_exit(0);
}
else
{
printf("in father process var=%d,num=%d\n",var,num);
}
return 0;
}
【实验步骤】
一、
1、打开终端,输入命令gedit 1_fork.c,在1_fork.c文件中输入1_fork.bmp 中的代码;
2、输入命令gcc 1_fork.c -o 1_fork,回车后显示无错误;
3、输入命令:./1_fork运行程序。

二、
1、打开终端,输入命令gedit 2_vfork.c,在2_vfork.c文件中输入2_vfork.bmp中的代码;
2、输入命令gcc 2_vfork.c -o 2_vfork,回车后显示无错误:
3、输入命令:./2_vfork运行程序。

【实验结果】
1、
从上面可以看到两次的运行结果不一样。

我们知道write函数是不带缓存的。

因为在fork之前调用write,所以其数据写到标准输出一次。

但是,标准 I/O库是带缓存的。

如果标准输出连到终端设备,则它是行缓存的,否则它是全缓存的。

当以交互方式运行该程序时,只得到printf输出的行一次,其原因是标准输出缓存由新行符刷新。

但是当将标准输出重新定向到一个文件时,却得到printf输出行两次。

其原因是,在fork之前调用了printf 一次,当调用fork时,该行数据仍在缓存中,然后在父进程数据空间复制到子进程中时,该缓存数据也被复制到子进程中。

于是那时父、子进程各自有了带该行内容的缓存。

在exit 之前的第二个printf将其数据添加到现存的缓存中。

当每个进程终止时,其缓存中的内容被写到相应文件中。

2、
因为我们知道vfork保证子进程先运行,子进程运行结束后,父进程才开始运行。

所以,第一次打印的是子进程的打印的信息,可以看到var值变成了11。

子进程结束后,父进程运行,父进程首先打印fork调用返回给他pid的值(就是子进程pid)。

以上我们可以看出,vfork创建的子进程和父进程运行的地址空间相同(子进程改变了var 值,父进程中的var 值也进行了改变).
【实验体会】
1、由fork创建的新进程被称为子进程(child process)。

该函数被调用一次,
但返回两次。

两次返回的区别是子进程的返回值是0,而父进程的返回值则是新子进程的进程ID。

2、将子进程ID返回给父进程的理由是:因为一个进程的子进程可以多于一
个,所有没有一个函数使一个进程可以获得其所有子进程的进程ID。

fork使子进程得到返回值0的理由是:一个进程只会有一个父进程,所以子进程总是可以调用
getppid以获得其父进程的进程ID(进程 ID 0总是由交换进程使用,所以一个子进程的进程ID不可能为0)。

3、vfork与fork一样都创建一个子进程; vfork和fork之间的另一个区别
是:vfork保证子进程先运行,在它调用exit之后父进程才可能被调度运行。

(如
果在调用这两个函数之前子进程依赖于父进程的进一步动作,则会导致死锁)。

相关主题