面试必备系列2:操作系统基础:进程的创建
实验二:进程的创建(小白系列第二弹~)🌸🌸🌸
🍀前言:
在实验前,需要先了解一些基本知识~🐴
实验所涉及的函数调用🌝:
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语句
。
*****🌻🌻🌻进程树:
二、根据进程树编写程序:🍁🍁🍁
编写程序创建进程树如图所示,在每个进程中显示当前进程标识符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
****进程树🤓🌴🌴🌴:
[实验感想]:
(1)系统是怎样创建进程的?🤔
一个进程调用fork()函数后,系统先给新的进程分配资源,例如存储数据和代码的空间。然后把原来的进程的所有值都复制到新的新进程中,只有少数值与原来的进程的值不同。相当于克隆了一个自己。
(2)当首次调用新创建进程时,其入口在哪里?🤔
fork调用成功后,子进程与父进程并发执行相同的代码。但由于子进程也继承了父进程的程序指针,所以子进程是从fork()后的语句开始执行(也就是新进程调用的入口)。fork()创建成功,返回值对子进程是0,对父进程是子进程的pid(一个正整数)。在调用fork()后,父进程和子进程均从下一条语句开始执行。另外fork在子进程和父进程中的返回值是不同的。在父进程中返回子进程的PID,而在子进程中返回0。所以可以在程序中检查PID的值,使父进程和子进程执行不同的分支。
(3)当前运行的程序(主进程)的父进程是什么?🤔
这里调用fork创建新进程的进程即为父进程,而相对应的为其创建出的进程则为子进程,因而除了进程0以外的进程都只有一个父进程,但一个进程可以有多个子进程。
小白更新系列第二弹!喜欢的朋友可以点个赞哦~😉😘
#笔记##读书笔记##学习路径##Linux#