操作系统实验
供大家交流学习,最好自己动手做,这样才有最深切的体会。
1.实验目的
学会通过基本的linux进程控制函数创建子进程,并实现协同工作。创建两个进程,让子进程读取输入,父进程等待子进程读完文件后继续执行。
2.实验软硬件环境
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()创建的子进程共享父进程的地址空间,且父进程被阻塞,只有当子进程运行完成后才能执行。相关阅读
(计算机的英文原词“computer”是指从事数据计算的人。而他们往往都需要借助某些机械计算设备或模拟计算机。) 沿着时间轴我们可以
1.如果C类子网的掩码为255.255.255.240,则包含的子网位数、子网数目、每个子网中的主机数目正确的是( )A类地址第1字节为网络地址,其
计算机软件专业是计算机科学的一个分支,和软件科学与技术专业相比较,计算机软件专业的侧重点在开发和技术的实际应用,而对软件开发的
原地址:http://bbs.chongbuluo.com/thread-366-1-1.html 追加: a、键盘的home,end,backspace,笔记本图键强大,别忽略 b、dos下善用home
考虑进行一些用户研究? 想知道哪些技术最有可能提供有用的结果? 可是却没有结果。因此我们编制了 7 项优秀的经过测试和实验的 UX