计算机操作系统第一次实验——进程的建立(报告版)

供大家交流学习,最好自己动手做,这样才有最深切的体会。


1.实验目的

    学会通过基本的Linux进程控制函数创建子进程,并实现协同工作。创建两个进程,让子进程读取输入,父进程等待子进程读完文件后继续执行。


2.实验软硬件环境
  • 安装Windows7的计算机
  • VMware软件,在其上安装有Ubuntu虚拟机

3.实验内容

1.掌握vfork()、fork()、waitpid()等函数的使用。

2.用以上函数在Linux操作系统创建子进程,子进程创建文件,父进程等待子进程完成后读取文件,并使父子进程分别修改资源,了解vfork()和fork()的区别。

相关函数介绍:

  • pid_t  vfork(void) 
    创建进程但子进程共享父进程的地址空间,即子进程对资源的改变会影响父进程,且强制优先子进程运行,父进程被阻塞,只有当子进程运行完后父进程才能运行。返回值: 若成功调用一次则返回两个值,子进程返回0,父进程返回子进程ID;否则,出错返回-1。
  • pid_t  fork(void) 
    子进程只是父进程的简单拷贝,子进程对资源的改变不会影响父进程,且父子进程可以并发运行。返回值: 若成功调用一次则返回两个值,子进程返回0,父进程返回子进程ID;否则,出错返回-1。
  • pid_t waitpid(pid_t pid,int * status,int options)                                                                                                  waitpid()会暂时停止目前进程的执行,直到有信号来到或子进程结束。如果在调用 waitpid()时子进程已经结束,则 waitpid()会立即返回子进程结束状态值。 子进程的结束状态值会由参数 status 返回,而子进程的进程识别码也会一起返回。如果不在意结束状态值,则参数 status 可以设成 NULL。参数 pid 为欲等待的子进程识别码,其他数值意义如下:                                                                                                                                              pid<-1 等待进程组识别码为 pid 绝对值的任何子进程。                                                                                   pid=-1 等待任何子进程,相当于 wait()。                                                                                                               pid=0 等待进程组识别码与目前进程相同的任何子进程。                                                                                           pid>0 等待任何子进程识别码为 pid 的子进程。                                                                                                         参数options提供了一些额外的选项来控制waitpid,参数 option 可以为 0 或可以用"|"运算符把它们连接起来使用,比如:ret=waitpid(-1,NULL,WNOHANG | WUNTRACED);如果我们不想使用它们,也可以把options设为0,如:ret=waitpid(-1,NULL,0);WNOHANG 若pid指定的子进程没有结束,则waitpid()函数返回0,不予以等待。若结束,则返回该子进程的ID。WUNTRACED 若子进程进入暂停状态,则马上返回,但子进程的结束状态不予以理会。WIFSTOPPED(status)宏确定返回值是否对应与一个暂停子进程。
  • pid_t  getpid(void) 
    返回子进程的pid。
  • pid_t  getppid(void) 
    返回父进程的pid,因为系统分配pid的时候遵循相邻递增的原则,所以一般子进程的pid比父进程的pid大1

4.实验程序及分析

实验程序:

#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include<sys/types.h>
#include<sys/wait.h>
#include<unistd.h>
//创建子进程fork()是简单的拷贝,而vfork()类似于线程,强制执行子进程让父进程阻塞,在子进程执行exit前子进程共享父进程的数据,子进程结束后在运行父进程。
int main()
{
	pid_t child;
	int i=0;
	printf("i = %d\n",i);
	char str[50];
	puts("1.excute");
	child = vfork();
	//child = fork();
//无论父子进程都是从fork或vfork后运行的,fork创建了子进程后,在子进程中返回0,在父进程中返回子进程的pid。

	puts("2.excute");
	
	if(child== -1)
	{
		perror("fork");
		puts("fail to create a sup process");
		exit(1);
	}
	else if(child == 0)
	{
		puts("\nin child:");
		printf("\tchild pid = %d\n",getpid());
		printf("\tchild ppid = %d\n",getppid());
		puts("writing in file :\n This is my work\n");
		FILE  *fp = fopen("123.txt","w");
		fprintf(fp,"%s","This is my work");		
		fclose(fp);
		i++;
		printf("i = %d\n",i);
		exit(0);
	}
	else
	{
		waitpid(child,NULL,0);
//等待pid为child的子进程运行,当子进程运行完后父进程运行。
		puts("\nin parent:");
		puts("reading form file ...");
		FILE *fp = fopen("123.txt","r");
		fgets(str,50,fp);
		puts(str);
		fclose(fp);
		i++;
		printf("i = %d\n",i);
		exit(0);
	}
	return 0;
}

终端结果:

vfork():

fork():


分析:

由以上代码,分别运行vfork()和fork()函产生子进程的结果有所不同,通过这些可以知道:

  • vfork()创建子进程后强制优先执行子进程,将父进程阻塞,只有当子进程运行完之后才运行父进程的代码。所以vfork()的运行结果中子进程的2.excute和父进程的2.excute没有连在一起。而是分开了。又因为父子进程是共享地址空间的,故子进程对i++的操作会影响父进程,父进程中输出i=2.
  • fork()运行结果就与vfork()不同了。因为fork()是对父进程的简单拷贝,且可以与父进程并发执行。故子进程的2.excute和父进程的2.excute连在一起。且子进程中i++对父进程没有影响,故父进程中的i=1.父进程中waitpid()函数使得父进程在运行else分支代码前要等待子进程。

5.实验截图

fork()

vfork()



6.实验心得体会
这次实验让我掌握了如何Linux在创建子进程,并且较为深入的了解了fork()和vfork()的区别。fork()创建的子进程只是对父进程的简单拷贝,并且父子进程并发执行。vfork()创建的子进程共享父进程的地址空间,且父进程被阻塞,只有当子进程运行完成后才能执行。



发布了47 篇原创文章 · 获赞 28 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/qq_41122796/article/details/80294532