草庐IT

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

yzy杨咩咩(◦˙▽˙◦) 2023-04-25 原文

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

目录

前言:

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

实验所涉及的函数调用:

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号和父进程标识符。

代码:
#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以外的进程都只有一个父进程,但一个进程可以有多个子进程。

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

有关作业必备:操作系统实验二【进程的创建】的更多相关文章

  1. ruby - 如何在 Ruby 中顺序创建 PI - 2

    出于纯粹的兴趣,我很好奇如何按顺序创建PI,而不是在过程结果之后生成数字,而是让数字在过程本身生成时显示。如果是这种情况,那么数字可以自行产生,我可以对以前看到的数字实现垃圾收集,从而创建一个无限系列。结果只是在Pi系列之后每秒生成一个数字。这是我通过互联网筛选的结果:这是流行的计算机友好算法,类机器算法:defarccot(x,unity)xpow=unity/xn=1sign=1sum=0loopdoterm=xpow/nbreakifterm==0sum+=sign*(xpow/n)xpow/=x*xn+=2sign=-signendsumenddefcalc_pi(digits

  2. python - 如何使用 Ruby 或 Python 创建一系列高音调和低音调的蜂鸣声? - 2

    关闭。这个问题是opinion-based.它目前不接受答案。想要改进这个问题?更新问题,以便editingthispost可以用事实和引用来回答它.关闭4年前。Improvethisquestion我想在固定时间创建一系列低音和高音调的哔哔声。例如:在150毫秒时发出高音调的蜂鸣声在151毫秒时发出低音调的蜂鸣声200毫秒时发出低音调的蜂鸣声250毫秒的高音调蜂鸣声有没有办法在Ruby或Python中做到这一点?我真的不在乎输出编码是什么(.wav、.mp3、.ogg等等),但我确实想创建一个输出文件。

  3. ruby - 使用 Vim Rails,您可以创建一个新的迁移文件并一次性打开它吗? - 2

    使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta

  4. ruby-on-rails - 无法使用 Rails 3.2 创建插件? - 2

    我对最新版本的Rails有疑问。我创建了一个新应用程序(railsnewMyProject),但我没有脚本/生成,只有脚本/rails,当我输入ruby./script/railsgeneratepluginmy_plugin"Couldnotfindgeneratorplugin.".你知道如何生成插件模板吗?没有这个命令可以创建插件吗?PS:我正在使用Rails3.2.1和ruby​​1.8.7[universal-darwin11.0] 最佳答案 随着Rails3.2.0的发布,插件生成器已经被移除。查看变更日志here.现在

  5. ruby - 在 jRuby 中使用 'fork' 生成进程的替代方案? - 2

    在MRIRuby中我可以这样做:deftransferinternal_server=self.init_serverpid=forkdointernal_server.runend#Maketheserverprocessrunindependently.Process.detach(pid)internal_client=self.init_client#Dootherstuffwithconnectingtointernal_server...internal_client.post('somedata')ensure#KillserverProcess.kill('KILL',

  6. ruby - 如何使用 RSpec::Core::RakeTask 创建 RSpec Rake 任务? - 2

    如何使用RSpec::Core::RakeTask初始化RSpecRake任务?require'rspec/core/rake_task'RSpec::Core::RakeTask.newdo|t|#whatdoIputinhere?endInitialize函数记录在http://rubydoc.info/github/rspec/rspec-core/RSpec/Core/RakeTask#initialize-instance_method没有很好的记录;它只是说:-(RakeTask)initialize(*args,&task_block)AnewinstanceofRake

  7. ruby - 通过 ruby​​ 进程共享变量 - 2

    我正在编写一个gem,我必须在其中fork两个启动两个webrick服务器的进程。我想通过基类的类方法启动这个服务器,因为应该只有这两个服务器在运行,而不是多个。在运行时,我想调用这两个服务器上的一些方法来更改变量。我的问题是,我无法通过基类的类方法访问fork的实例变量。此外,我不能在我的基类中使用线程,因为在幕后我正在使用另一个不是线程安全的库。所以我必须将每个服务器派生到它自己的进程。我用类变量试过了,比如@@server。但是当我试图通过基类访问这个变量时,它是nil。我读到在Ruby中不可能在分支之间共享类变量,对吗?那么,还有其他解决办法吗?我考虑过使用单例,但我不确定这是

  8. ruby - 为什么 SecureRandom.uuid 创建一个唯一的字符串? - 2

    关闭。这个问题需要detailsorclarity.它目前不接受答案。想改进这个问题吗?通过editingthispost添加细节并澄清问题.关闭8年前。Improvethisquestion为什么SecureRandom.uuid创建一个唯一的字符串?SecureRandom.uuid#=>"35cb4e30-54e1-49f9-b5ce-4134799eb2c0"SecureRandom.uuid方法创建的字符串从不重复?

  9. ruby - 有人可以帮助解释类创建的 post_initialize 回调吗 (Sandi Metz) - 2

    我正在阅读SandiMetz的POODR,并且遇到了一个我不太了解的编码原则。这是代码:classBicycleattr_reader:size,:chain,:tire_sizedefinitialize(args={})@size=args[:size]||1@chain=args[:chain]||2@tire_size=args[:tire_size]||3post_initialize(args)endendclassMountainBike此代码将为其各自的属性输出1,2,3,4,5。我不明白的是查找方法。当一辆山地自行车被实例化时,因为它没有自己的initialize方法

  10. ruby - 使用多个数组创建计数 - 2

    我正在尝试按0-9和a-z的顺序创建数字和字母列表。我有一组值value_array=['0','1','2','3','4','5','6','7','8','9','a','b','光盘','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','','u','v','w','x','y','z']和一个组合列表的数组,按顺序,这些数字可以产生x个字符,比方说三个list_array=[]和一个当前字母和数字组合的数组(在将它插入列表数组之前我会把它变成一个字符串,]current_combo['0','0','0']

随机推荐