作业必备:操作系统实验二【进程的创建】

优秀的进程,从创建开始~

在这里插入图片描述

前言:

在实验前,需要先了解一些基本知识~

实验所涉及的函数调用:

1、fork函数

功能:***创建一个新的子进程***。其子进程会复制父进程的数据与堆栈空间,并继承父进程的用户代码、组代码、环境变量、已打开的文件代码、工作目录和资源限制。注意:子进程总是从fork之后开始复制父进程的。
系统调用格式: int fork()
如果Fork调用成功,则在父进程会返回新建立的子进程标识符(PID),而在新建立的子进程中则返回0。如果fork失败则直接返回-1。
调用fork()函数需要包含头文件#include <unistd.h>

2、wait函数

功能:等待子进程运行结束。如果子进程没有完成,父进程一直等待。wait( )将调用进程挂起,直至其子进程因暂停或终止而发来软中断信号为止。如果在wait( )前已有子进程暂停或终止,则调用进程做适当处理后便返回。调用wait()函数需要包含头文件#include <sys/wait.h>
系统调用格式:int wait(status)

3、exit函数

功能:终止进程的执行。其中,status是返回给父进程的一个整数。为了及时回收进程所占用的资源并减少父进程的干预,UNIX/LINUX利用exit( )来实现进程的自我终止,通常父进程在创建子进程时,应在进程的末尾安排一条exit( )语句,使子进程自我终止。exit(0)表示进程正常终止,exit(1)表示进程运行有错,异常终止。调用exit()函数需要包含头文件:#include<stdlib.h>
系统调用格式:void exit(status)

—————————————————————

提示:以下是本篇文章正文内容,下面案例可供参考

正文:

[实验目的]:

1、掌握进程的概念,进一步理解进程和程序的区别。
2、认识和了解并发执行的实质。
3、掌握fork()、wait()、exit()函数。

[实验内容]:

一、进程的创建:

在Linux系统,创建C文件的方法,详情请见我的第一篇博文~

进程的创建:编写一段程序,使用系统调用fork( )创建两个子进程,在系统中有一个父进程和两个子进程活动。让每个进程在屏幕上显示一个字符;父进程显示字符“f”,两个子进程分别显示字符“s” 和“d”。多次运行可执行程序,观察记录屏幕上的显示结果,并分析原因。画出进程树的结构图。

代码:

#include<stdio.h>
#include <unistd.h>
#include<stdlib.h>
#include<sys/wait.h>
  int  main()
    { int  p1, p2,pid;
    while((p1=fork())== -1);
    printf("ok....\n");  // 创建成功为止
    if(p1==0){    //如果是子进程
       
       		putchar('s');
       		printf("  ");
       		printf("i am the child1:%d   ",getpid());
       		printf("the return value:%d\n",p1);
       		exit(0);
       
       }
    else            
      { while((p2=fork())==-1);
        if(p2==0){ 
        	putchar('d');
            printf("  ");
            printf("i am the child2:%d   ",getpid());
            printf("the return value:%d\n",p2);
            }
           
        else{
            pid=wait(0);
            putchar('f');
            printf("  ");
            printf("i am the father:%d   the return value:%d\n",getpid(),pid);      
       }
     } 
     }

结果:

yzy@yzy-virtual-machine:~/new$ ./dd.out
ok....
ok....
s  i am the child1:2830   the return value:0
d  i am the child2:2831   the return value:0
f  i am the father:2829   the return value:2830

***分析:如上图,可清晰得出进程间的关系。

由前言可知,父进程会返回新建立的子进程标识符(PID),而在新建立的子进程中则返回0。

**** OK出现两次的原因

由前言可知,子进程总是从fork之后开始复制父进程的!!所以在第一个fork 语句后,有两个进程,一个是父进程,另一个是子进程1,去执行OK语句

******进程树:

father
child1
child2
二、根据进程树编写程序:

##编写程序创建进程树如图所示,在每个进程中显示当前进程标识符PID号和父进程标识符。
编写程序创建进程树如图1和图2所示,在每个进程中显示当前进程标识符PID号和父进程标识符。

代码:
#include<stdio.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <stdlib.h>
 
int main(){
    	int pid,pid2,pid3,pid4;
        pid=fork();
        if(pid<0)       
                printf("error occurred!\n");
        else if(pid==0) /* 如果是子进程 */
                {
                        printf("我是子进程b,进程号是%d\n",getpid());
                        int pid1;
                        pid1 = fork();
                        if(pid1==0){
                                printf("我是子进程b的子进程c,进程号是%d\n",getpid());
                                exit(0);
                        }
                }
        else{
                printf("我是父进程a,进程号是%d\n",getpid());
                pid4=fork();
                if(pid4==0){
                        printf("我是子进程d,进程号是%d\n",getpid());                   
                        pid2=fork();      
                        if(pid2==0){
                      	  printf("我是子进程d的子进程e,进程号是%d\n",getpid());
                    }
                        else{
                          pid3=fork();
                          if(pid3==0){
                          printf("我是子进程d的子进程f,进程号是%d\n",getpid());
                          exit(0);}}
                                                  }}       
        return 0;
}

结果:

yzy@yzy-virtual-machine:~/new$ ./c.out
我是父进程a,进程号是3187
我是子进程b,进程号是3188
我是子进程d,进程号是3189
我是子进程b的子进程c,进程号是3190
我是子进程d的子进程e,进程号是3191
我是子进程d的子进程f,进程号是3192
三、根据程序画进程树:

在Linux系统中运行下面的程序,最多可产生多少个进程,试画出进程家族树。
main()
{
fork();
fork();
}

代码:
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include <sys/wait.h>

int main()
{int m,n,k;
m=fork();
printf("hee   ");
printf("pid:%d   ",getpid());
printf("the return value:%d\n",m);

n=fork();
printf("ha    ");
printf("pid:%d   ",getpid());
printf("the return value:%d\n",n);

}

结果:

yzy@yzy-virtual-machine:~/new$ ./hh.out
hee   pid:3312   the return value:3313
hee   pid:3313   the return value:0
ha    pid:3312   the return value:3314
ha    pid:3313   the return value:3315
ha    pid:3314   the return value:0
ha    pid:3315   the return value:0

*****进程树

father:3312
child1:3313
child2:3314
child3:3315

[实验感想]:

(1)系统是怎样创建进程的?
一个进程调用fork()函数后,系统先给新的进程分配资源,例如存储数据和代码的空间。然后把原来的进程的所有值都复制到新的新进程中,只有少数值与原来的进程的值不同。相当于克隆了一个自己。
(2)当首次调用新创建进程时,其入口在哪里?
fork调用成功后,子进程与父进程并发执行相同的代码。但由于子进程也继承了父进程的程序指针,所以子进程是从fork()后的语句开始执行(也就是新进程调用的入口)。fork()创建成功,返回值对子进程是0,对父进程是子进程的pid(一个正整数)。在调用fork()后,父进程和子进程均从下一条语句开始执行。另外fork在子进程和父进程中的返回值是不同的。在父进程中返回子进程的PID,而在子进程中返回0。所以可以在程序中检查PID的值,使父进程和子进程执行不同的分支。
(3)当前运行的程序(主进程)的父进程是什么?
这里调用fork创建新进程的进程即为父进程,而相对应的为其创建出的进程则为子进程,因而除了进程0以外的进程都只有一个父进程,但一个进程可以有多个子进程。

小白更新系列第二弹!喜欢的朋友可以点个赞哦~

  • 53
    点赞
  • 217
    收藏
    觉得还不错? 一键收藏
  • 25
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 25
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值