第9章 进程fork
进程创建之fork系统调用
4 进程创建 (1)4.1 实验内容及要求 (1)4.2 实验目的 (1)4.3 实验环境 (1)4.4 实验思路 (1)4.5 实验代码 (2)4.6 运行结果 (3)4.7 实验心得 (3)4 进程创建4.1 实验内容及要求利用fork()系统调用创建进程。
要求如下:编制一段程序,使用系统调用fork( )创建两个子进程,这样在此程序运行时,在系统中就有一个父进程和两个子进程在活动。
每一个进程在屏幕上显示一个字符,其中父进程显示字符A,子进程分别显示字符 B和字符C。
试观察、记录并分析屏幕上进程调度的情况。
4.2 实验目的了解进程的创建过程,进一步理解进程的概念,明确进程和程序的区别。
4.3 实验环境Ubuntu 18.04.1 LTS 64位,编译器gcc 7.3.0 (Ubuntu 7.3.0-16ubuntu3)4.4 实验思路(1)可用fork()系统调用来创建一个新进程。
系统调用格式:pid=fork()fork()返回值意义如下:=0:若返回值为0,表示当前进程是子进程。
>0:若返回值大于0,表示当前进程是父进程,返回值为子进程的pid值。
<0:若返回值小于0,表示进程创建失败。
如果fork()调用成功,它向父进程返回子进程的pid,并向子进程返回0,即fork()被调用了一次,但返回了两次。
此时OS在内存中建立一个新进程,所建的新进程是调用fork()父进程的副本,称为子进程。
子进程继承了父进程的许多特性,并具有与父进程完全相同的用户级上下文。
父进程与子进程并发执行。
(2)编译和执行的方法:编译:在shell提示符下输入gcc 源文件名 -o 可执行文件名运行:在shell提示符下输入 ./可执行文件名4.5 实验代码#include<unistd.h>#include<stdlib.h>#include<stdio.h>int main(void) {pid_t p1=fork();pid_t p2=fork(); //迭代调用fork(),创建三个新进程printf("this is parent, pid = %d\n", getpid()); //父进程if(p1<0||p2<0){ //fork()失败printf("fork failed with p1=%d, p2=%d\n", p1, p2);exit(1);}if(p1==0&&p2==0){ //子进程B创建的子进程D,即孙进程printf("D in grandson Damson, pid = %d\n", getpid());}if(p1==0&&p2>0){ //父进程创建的子进程Bprintf("B in child Blueberry, pid = %d\n", getpid());}if(p1>0&&p2==0){ //父进程创建的子进程Cprintf("C in child Carambola, pid = %d\n", getpid());}if(p1>0&&p2>0){ //父进程printf("A in parent Apple, pid = %d\n", getpid());}return 0;}4.6 运行结果编译源文件4.c得到可执行文件文件4,运行如下:4.7 实验心得每次调用fork()函数,从代码层理解,相当于自fork()之后的所有代码复制了一份给新进程。
f o r k ( ) 介 绍
多进程中的fork一、fork入门知识一个进程,包括代码、数据和分配给进程的资-源。
fork()函数通过系统调用创建一个与原来进程几乎完全相同的进程,也就是两个进程可以做完全相同的事,但如果初始参数或者传入的变量不同,两个进程也可以做不同的事。
一个进程调用fork()函数后,系统先给新的进程分配资-源,例如存储数据和代码的空间。
然后把原来的进程的所有值都复制到新的新进程中,只有少数值与原来的进程的值不同。
相当于克隆了一个自己。
我们来看一个例子:* fork_test.c* version 1* Created on: 2010-5-29* Author: wangth#include unistd.h#include stdio.hint main ()pid_t fpid; --fpid表示fork函数返回的值int count=0;fpid=fork();if (fpid 0)printf("error in fork!");else if (fpid == 0) {printf("i am the child process, my process id is %d-n",getpid());printf("我是爹的儿子-n");--对某些人来说中文看着更直白。
count++;printf("i am the parent process, my process id is %d-n",getpid());printf("我是孩子他爹-n");count++;printf("统计结果是: %d-n",count);return 0;运行结果是:i am the child process, my process id is 5574我是爹的儿子统计结果是: 1i am the parent process, my process id is 5573我是孩子他爹统计结果是: 1在语句fpid=fork()之前,只有一个进程在执行这段代码,但在这条语句之后,就变成两个进程在执行了,这两个进程的几乎完全相同,将要执行的下一条语句都是if(fpid0)……为什么两个进程的fpid不同呢,这与fork函数的特性有关。
linux操作系统下fork函数理解
linux操作系统下fork函数理解在Linux操作系统中,fork函数是一个非常重要的系统调用,它用于创建一个新的进程。
本文将详细解释fork函数的作用、用法和实现原理,并介绍如何利用fork函数实现进程间通信以及避免一些常见的问题。
一、fork函数的作用和用法在Linux系统中,fork函数用于创建一个新的进程,该进程是调用fork函数的进程的一个副本。
具体而言,fork函数会创建一个新的进程,称为子进程,而调用fork函数的进程被称为父进程。
子进程从fork函数返回的地方开始执行,而父进程则继续执行fork函数之后的代码。
简单来说,fork函数的作用就是将一个进程复制成两个几乎完全相同的进程,但它们具有不同的进程ID(PID)。
fork函数的用法非常简单,只需要在程序中调用fork()即可。
具体代码如下所示:```c#include <stdio.h>#include <sys/types.h>#include <unistd.h>int main() {pid_t pid = fork();if (pid == 0) {// 子进程代码} else if (pid > 0) {// 父进程代码} else {// fork失败的处理代码}return 0;}```在上述代码中,首先使用pid_t类型的变量pid存储fork函数的返回值。
如果pid等于0,则表示当前执行的是子进程的代码;如果pid大于0,则表示当前执行的是父进程的代码;如果pid小于0,则表示fork函数调用失败。
二、fork函数的实现原理在Linux系统中,fork函数的实现是通过复制父进程的内存空间来创建子进程的。
具体来说,fork函数会创建一个新的进程控制块(PCB),并将父进程的PCB全部复制到子进程的PCB中,包括代码段、数据段、堆栈等。
由于子进程是父进程的一个副本,所以它们的代码和数据是完全相同的。
进程控制之fork函数
进程控制之fork函数⼀个现有进程可以调⽤fork函数创建⼀个新进程。
#include <unistd.h>pid_t fork( void );返回值:⼦进程中返回0,⽗进程中返回⼦进程ID,出错返回-1由fork创建的新进程被称为⼦进程(child process)。
fork函数被调⽤⼀次,但返回两次。
两次返回的唯⼀区别是⼦进程的返回值是0,⽽⽗进程的返回值则是新⼦进程的进程ID。
将⼦进程ID返回给⽗进程的理由是:因为⼀个进程的⼦进程可以有多个,并且没有⼀个函数使⼀个进程可以获得其所有⼦进程的进程ID。
fork使⼦进程得到返回值0的理由是:⼀个进程只会有⼀个⽗进程,所以⼦进程总是可以调⽤getppid以获得其⽗进程的进程ID(进程ID 0总是由内核交换进程使⽤,所以⼀个⼦进程的进程ID不可能为0)。
⼦进程和⽗进程继续执⾏fork调⽤之后的指令。
⼦进程是⽗进程的副本。
例如,⼦进程获得⽗进程的数据空间、堆和栈的副本。
注意,这是⼦进程所拥有的副本。
⽗、⼦进程并不共享这些存储空间部分。
⽗、⼦进程共享正⽂段(text,代码段)。
由于在fork之后经常跟随着exec,所以现在的很多实现并不执⾏⼀个⽗进程数据段、栈和堆的完全复制。
作为替代,使⽤了写时复制(Copy-On-Write,COW)技术。
这些区域由⽗、⼦进程共享,⽽且内核将它们的访问权限改变为只读的。
如果⽗、⼦进程中的任⼀个试图修改这些区域,则内核只为修改区域的那块内存制作⼀个副本,通常是虚拟存储器系统中的⼀“页”。
Linux 2.4.22提供了另⼀种新进程创建函数——clone(2)系统调⽤。
这是⼀种fork的泛型,它允许调⽤者控制哪些部分由⽗、⼦进程共享。
程序清单8-1中的程序演⽰了fork函数,从中可以看到⼦进程对变量所作的改变并不影响⽗进程中该变量的值。
程序清单8-1 fork函数⽰例[root@localhost apue]# cat prog8-1.c#include "apue.h"int glob = 6; /* external variable in initialized data */char buf[] = "a write to stdout\n";intmain(void){int var; /* automatic variable on the stack */pid_t pid;var = 88;if(write(STDOUT_FILENO, buf, sizeof(buf) - 1) != sizeof(buf) -1)err_sys("write error");printf("before fork\n"); /* we don't flush stdout */if((pid = fork()) < 0){err_sys("fork error");}else if(pid == 0) /* child */{glob++; /* modify variables */var++;}else{sleep(2); /* parent */}printf("pid = %d, glob = %d, var = %d\n", getpid(), glob, var);exit(0);}如果执⾏此程序则得到:[root@localhost apue]# ./prog8-1a write to stdoutbefore forkpid = 13367, glob = 7, var = 89⼦进程的变量值改变了pid = 13366, glob = 6, var = 88⽗进程的变量值没有改变[root@localhost apue]# ./prog8-1 > tmp.out[root@localhost apue]# cat tmp.outa write to stdoutbefore forkpid = 13369, glob = 7, var = 89before forkpid = 13368, glob = 6, var = 88⼀般来说,在fork之后是⽗进程先执⾏还是⼦进程先执⾏是不确定的。
linux中利用fork函数创建进程的方法
linux中利用fork函数创建进程的方法摘要:一、引言二、Linux中进程与线程的概念1.进程2.线程三、fork函数简介1.函数定义2.函数作用四、fork函数创建进程的步骤1.调用fork函数2.子进程与父进程的资源分配3.子进程与父进程的执行顺序五、fork函数创建进程的实例1.程序代码2.程序运行结果六、fork函数的优缺点1.优点2.缺点七、总结与展望正文:一、引言在Linux操作系统中,进程是系统资源分配的基本单位,而进程的创建是编程中不可或缺的操作。
本文将介绍在Linux中利用fork函数创建进程的方法,并通过实例进行详细说明。
二、Linux中进程与线程的概念1.进程进程是计算机中程序执行的基本单位,它包括程序代码、数据、堆栈等资源。
每个进程都有独立的内存空间,使得进程之间相互独立,不会互相干扰。
2.线程线程是进程内部的一个执行流程,它是调度的基本单位。
一个进程可以包含多个线程,线程共享进程的内存空间和其他系统资源。
线程相比于进程,更易于管理和调度,能够提高系统的利用率。
三、fork函数简介1.函数定义fork函数是Linux系统中用于创建进程的函数,其原型如下:```cpid_t fork(void);```2.函数作用fork函数创建一个与父进程几乎相同的子进程,子进程与父进程共享内存空间,但具有独立的进程ID。
调用fork函数后,返回子进程的进程ID。
四、fork函数创建进程的步骤1.调用fork函数在编写程序时,调用fork函数即可创建一个子进程。
2.子进程与父进程的资源分配fork函数创建子进程时,会为子进程分配必要的资源,如进程ID、内存空间、文件描述符等。
子进程与父进程共享资源,如进程计数、进程名称等。
3.子进程与父进程的执行顺序调用fork函数后,子进程与父进程的执行顺序如下:- 父进程首先执行- 然后创建子进程- 子进程执行五、fork函数创建进程的实例1.程序代码以下是一个简单的利用fork函数创建进程的C程序:```c#include <stdio.h>#include <unistd.h>int main(){pid_t pid = fork();if (pid < 0){printf("fork failed");return 1;}else if (pid == 0){printf("I am a child process ");}else{printf("I am a parent process ");}return 0;}```2.程序运行结果运行上述程序,输出结果如下:```I am a parent processI am a child process```六、fork函数的优缺点1.优点- 简洁易懂的接口,易于使用- 子进程与父进程资源共享,减少内存占用- 子进程可独立执行,提高系统利用率2.缺点- 子进程与父进程的内存空间共享可能导致内存泄漏等问题- 进程切换开销较大,影响性能七、总结与展望本文详细介绍了在Linux中利用fork函数创建进程的方法,通过实例进行了深入剖析。
使用fork创建进程
使用fork创建进程1.实验目的(1)理解Linux实现系统调用的机制;(2)理解并掌握fork系统调用创建新进程的过程和原理;(3)掌握vi(vim)、GCC和GDB的使用。
2.实验内容(1)通过编程验证fork函数的实现机制,并理解写时拷贝COW的意义;(2)使用fork和exec函数创建新进程。
3.实验方法(实验步骤)实验二步骤:第一步:双击打开进入linux的终端,用vi新建一个Del_Sleep.c的文件第二步:创建成功之后,输入“a”或“o”或“i”进行插入编辑写入模式第三步:开始写我们的代码第四步:代码编辑完成之后,按“Esc”间退出编辑模式第五步:输入“:wq”对我们刚才编辑的代码进行保存退出第六步:输入“gcc Del_Sleep.c -o Del_Sleep ”命令运行代码的编译成可执行文件第七步:然后输入“./a.out”或者“./ Del_Sleep”进行代码的运行,得到我们程序的运行结果实验三步骤:第一步:双击打开进入linux的终端,用vi新建一个Three_Fork.c的文件第二步:创建成功之后,输入“a”或“o”或“i”进行插入编辑写入模式第三步:开始写我们的代码第四步:代码编辑完成之后,按“Esc”间退出编辑模式第五步:输入“:wq”对我们刚才编辑的代码进行保存退出第六步:输入“gcc Three _Fork.c -o Three _Fork”命令运行代码的编译成可执行文件第七步:然后输入“./a.out”或者“./ Three_Fork”进行代码的运行,这时候就可以得到我们程序的结果实验四步骤:第一步:双击打开进入linux的终端,用vi新建一个two_before.c的文件第二步:创建成功之后,输入“a”或“o”或“i”进行插入编辑写入模式第三步:开始写我们的代码第四步:代码编辑完成之后,按“Esc”间退出编辑模式第五步:输入“:wq”对我们刚才编辑的代码进行保存退出第六步:输入“gcc two_before.c -o two_before ”命令运行代码的编译成可执行文件第七步:然后输入“./ two_before>ou.tst”进行代码的运行,第八步:继续输入“cat ou.tst”这时候就可以查看我们程序的结果4.实验过程(源代码、配置清单必须带注释)注释:源码中出现的定义pid为进程号,ppid为父进程号,getppid为获取父进程id,getpid为获取子进程id,sleep为睡眠时钟,fork函数为一次调用,返回两个值,子进程返回0,父进程返回子进程id标记,出错返回-1,exec函数把程序(保存在磁盘某个目录中的可执行文件)读入内存并执行,Exec函数不创建进程,而是用一个新的程序替换当前进程的代码段、数据段和堆栈。
fork 用法
fork 用法fork 是一个系统调用,用于创建一个新的进程。
新的进程是原始进程(父进程)的一个副本,称为子进程。
这两个进程在几乎所有方面都是相同的,包括代码、数据和上下文。
在编程中,fork 通常用于创建一个新的进程,以便在子进程中执行不同的任务。
基本用法:#include <unistd.h>#include <stdio.h>int main() {pid_t pid = fork();if (pid == -1) {// 处理 fork 失败的情况perror("fork");return 1;}if (pid == 0) {// 子进程执行的代码printf("This is the child process (PID=%d)\n", getpid());} else {// 父进程执行的代码printf("This is the parent process (PID=%d), child PID=%d\n", getpid(), pid);}return 0;}注意事项:fork 返回两次,一次在父进程中返回子进程的PID,另一次在子进程中返回0。
在父子进程中的变量和状态是相互独立的,它们不会相互影响。
在fork 之后,通常会使用exec 函数族在子进程中加载新的程序。
父子进程的执行顺序和执行时间是不确定的,取决于操作系统的调度。
示例:在子进程中执行其他程序#include <unistd.h>#include <stdio.h>#include <sys/wait.h>int main() {pid_t pid = fork();if (pid == -1) {perror("fork");return 1;}if (pid == 0) {// 子进程中执行其他程序execl("/bin/ls", "ls", "-l", NULL);} else {// 等待子进程结束wait(NULL);printf("Parent process done.\n");}return 0;}这个例子中,父进程创建了一个子进程,子进程通过 execl 加载了 /bin/ls 程序。
fork实现原理
fork实现原理Fork 实现原理在操作系统中,fork 是基本的进程创建操作之一,它会复制当前进程的所有资源创建出一个新的进程。
在本文中,我们将探讨 fork 的实现原理。
1. fork 函数在 Unix 系统中,fork 的实现是通过系统调用来完成的。
用户程序调用 fork 函数之后,系统内核(kernel)会复制一份当前进程的所有资源并创建出一个新的进程,这个新的进程也称为子进程。
在父进程中,fork 函数会返回子进程的 PID(process ID),而在子进程中,它会返回 0。
2. 内存结构在 fork 函数被调用的时候,操作系统会将当前进程的虚拟地址空间复制一份给子进程。
这样,子进程就有了自己的独立内存空间,可以与父进程并行执行。
注意,这里只是指虚拟地址空间,物理内存并没有被复制。
操作系统会使用写时复制(Copy-on-write)技术,即在子进程需要修改内存中某个值时才会开辟新的物理内存空间,避免了大量的内存复制。
这种技术可以大大提高程序的运行效率。
3. 文件描述符和文件表文件描述符是一个整数,用来标识一个特定的文件或资源。
在 Unix系统中,每一个进程都有属于自己的文件表,其中存储了打开的文件列表以及文件的各种元信息。
在 fork 操作中,子进程会继承父进程的全部文件描述符和文件表。
这意味着在子进程中打开或关闭文件等操作都会影响父进程的文件,相当于父子进程共享文件。
4. 进程控制块进程控制块(Proc Control Block,PCB)是操作系统内部维护的一个数据结构,存储了进程的各种属性。
在 fork 后,子进程会获取一份父进程的 PCB,包括进程 ID、状态、优先级等信息。
这使得系统可以在同一个进程中对父子进程进行管理和调度。
5. 总结fork 是操作系统中基本的进程创建操作之一,在 Unix 系统中是通过系统调用实现的。
在 fork 实现中,操作系统会复制一份当前进程的虚拟地址空间、文件描述符以及进程控制块,并使用写时复制技术避免大量的内存复制。
fork()的用法
fork()的用法
fork() 是一个用于创建新进程的系统调用。
具体来说,它会复制当前进程,然后创建一个与原进程几乎完全相同的新进程。
新进程(子进程)会继承父进程的所有资源,包括代码、数据和系统资源。
fork() 的基本用法如下:
1. 调用 fork() 函数,它会返回两次:一次是在父进程中,返回新创建子进程的 PID;另一次是在子进程中,返回 0。
2. 在父进程中,fork() 返回新创建子进程的 PID,可以通过这个 PID 对子进程进行操作。
3. 在子进程中,fork() 返回 0,可以通过返回值来区分当前是父进程还是子进程。
fork() 的常见用法包括:
1. 创建新的子进程:通过调用 fork() 函数,可以创建一个与原进程几乎完全相同的新进程。
新进程会继承父进程的所有资源,包括代码、数据和系统资源。
2. 实现多线程:fork() 可以用来实现多线程编程。
在每个线程中调用 fork() 函数,可以创建多个子进程,从而实现并发执行。
3. 实现并行计算:通过 fork() 函数创建多个子进程,每个子进程执行不同的任务,可以实现并行计算,提高程序的执行效率。
需要注意的是,fork() 函数的使用需要谨慎,因为它涉及到进程的创建和复制。
如果使用不当,可能会导致资源泄漏、竞争条件等问题。
因此,在使用fork() 函数时需要仔细考虑程序的逻辑和安全性。
linux中fork的作用
linux中fork的作用在Linux中,fork(是一个非常重要的系统调用。
它的作用是创建一个新的进程,这个新的进程被称为子进程,而原始进程被称为父进程。
fork(系统调用会在父进程和子进程之间复制一份相同的当前执行状态,包括程序的代码、数据、堆栈以及其他相关资源。
当一个进程调用fork(时,操作系统会将当前的进程映像复制一份,包括进程的地址空间、文件描述符、信号处理器等。
然后操作系统会分配一个唯一的进程ID(PID)给子进程,父进程和子进程会分别返回子进程的PID和0。
子进程会从fork(调用的位置开始执行,而父进程则继续执行接下来的指令。
fork(的作用有以下几个方面:1. 多任务处理:通过fork(,一个进程可以生成多个子进程,每个子进程可以执行不同的任务。
这种多任务处理的能力是Linux操作系统的基石之一,它允许同时运行多个进程,从而提高系统的并发性和响应性能。
2. 进程间通信:fork(可以为不同的进程提供通信机制。
子进程可以通过进程间通信(IPC)机制与父进程进行数据交换,包括管道、消息队列、共享内存等。
这样实现了进程间的数据共享和协同工作。
3. 服务器模型:fork(在服务器模型中起到关键作用。
通过fork(,一个服务器进程可以创建多个子进程来处理客户端请求。
子进程在接收到请求后,可以独立地为客户端提供服务,这样能够极大地提高服务器的吞吐量和并发处理能力。
4. 资源管理:通过fork(,Linux可以对资源进行有效的管理。
当一个进程需要一个完全相同的副本来执行其他任务时,可以使用fork(来复制当前进程的状态。
这种状态的复制可以节省时间和资源,避免了重新加载和初始化的开销。
5. 守护进程创建:守护进程是在后台执行的长时间运行的进程,不依赖于任何终端。
通过调用fork(,父进程可以使自己成为一个后台进程,并终止自己,而子进程则变为一个孤儿进程并被init进程接管。
这样,守护进程就能够在系统启动后一直运行,提供服务。
fork的底层实现方式
fork的底层实现方式Fork是Unix系统中的一个重要概念,它可以创建一个新的进程,这个新的进程是原进程的一个副本。
在Unix系统中,每个进程都有一个唯一的进程ID,fork会为新的进程分配一个新的进程ID,并且这个新的进程会继承原进程的所有资源,包括代码段、数据段、堆栈、文件描述符等等。
那么,fork的底层实现方式是什么呢?在Unix系统中,fork是通过系统调用来实现的。
当一个进程调用fork时,操作系统会为新的进程创建一个新的进程控制块(PCB),并将原进程的PCB复制一份到新的进程的PCB中。
这样,新的进程就拥有了原进程的所有资源。
在fork的实现过程中,操作系统会为新的进程分配一个新的虚拟地址空间,并将原进程的虚拟地址空间复制一份到新的进程的虚拟地址空间中。
这个过程被称为“写时复制”(Copy-On-Write)。
也就是说,当新的进程需要修改某个资源时,操作系统会将这个资源从原进程的虚拟地址空间中复制一份到新的进程的虚拟地址空间中,然后再进行修改。
这样,就避免了资源的重复复制,提高了fork的效率。
除了资源的复制外,fork还需要进行一些其他的操作。
例如,新的进程需要拥有自己的进程ID、父进程ID、用户ID、组ID等等。
操作系统会为新的进程分配一个新的进程ID,并将原进程的进程ID作为新进程的父进程ID。
此外,新的进程还需要重新打开文件描述符、清空信号处理器等等。
总的来说,fork的底层实现方式是通过系统调用来实现的。
在实现过程中,操作系统会为新的进程创建一个新的进程控制块,并将原进程的所有资源复制一份到新的进程中。
为了提高效率,操作系统采用了“写时复制”的技术,避免了资源的重复复制。
此外,新的进程还需要进行一些其他的操作,例如重新打开文件描述符、清空信号处理器等等。
Linux编程之进程fork()详解及实例
Linux编程之进程fork()详解及实例Linux fork()详解:在开始之前,我们先来了解⼀些基本的概念:1. 程序,没有在运⾏的可执⾏⽂件进程, 运⾏中的程序2. 进程调度的⽅法:按时间⽚轮转先来先服务短时间优先按优先级别3. 进程的状态:就绪 ->> 运⾏ ->> 等待运⾏ ->> 就绪 //时间⽚完了等待 ->> 就绪 //等待的条件完成了查看当前系统进程的状态 ps auxfstatus:D Uninterruptible sleep (usually IO)R Running or runnable (on run queue)S Interruptible sleep (waiting for an event to complete)T Stopped, either by a job control signal or because it is being traced.W paging (not valid since the 2.6.xx kernel)X dead (should never be seen)Z Defunct ("zombie") process, terminated but not reaped by its parent.< high-priority (not nice to other users)N low-priority (nice to other users)L has pages locked into memory (for real-time and custom IO)s is a session leaderl is multi-threaded (using CLONE_THREAD, like NPTL pthreads do)+ is in the foreground process group4. ⽗进程/⼦进程 , 让⼀个程序运⾏起来的进程就叫⽗进程, 被调⽤的进程叫⼦进程5. getpid //获取当前进程的进程号getppid //获取当前进程的⽗进程号6. fork //创建⼀个⼦进程,创建出来的⼦进程是⽗进程的⼀个副本,除了进程号,⽗进程号不同。
fork创建进程的过程分析
fork创建进程的过程分析本⽂为我学习linux内核的总结。
1、概述 前⾯分析了系统调⽤的原理和过程。
本⽂分析fork这个系统调⽤,重点分析进程的创建主要动作和流程。
2、fork 系统调⽤的主要动作 如上图,fork、vfork、clone,最终都是调⽤do_fork。
不过他们之间的差异也可以在do_fork及后续代码中看到,不过这⾥不讲述。
do_fork 的主要逻辑为调⽤copy_process,⼜函数名就可以看到进程的⽣成逻辑就在copy_process. copy_process主要调⽤了:dup_task_struct()——主要是创建和复制进程copy_fs ——拷贝⽂件句柄之类的 copy_files ——拷贝⽂件句柄之类的copy_mm ——拷贝虚拟内存 copy_io ——拷贝io copy_thread ——拷贝thead_info信息下⾯我们着重分析 dup_task_struct 和 copy_thread 。
2.1 、dup_task_struct:申请内存,拷贝task_struct和thread_info 如上图所⽰,前⾯两个调⽤为申请task_struct、thread_info 的内存,arch_dup_task_struct就是将⽗进程的 task_struct 拷贝给⼦进程。
setup_thread_stack:这个函数是将⽗进程的堆栈thread_info拷贝给⼦进程。
2.2、copy_thread :准备栈信息如上图信息childregs保存⽗进程的堆栈信息,然后赋值给⼦进程堆栈。
右图pt_regs为系统调⽤开始通过save_all保存的信息。
同时可以看到如果是内核创建线程⾛的不同的分⽀,不同的处理。
上⾯可以看到childregs->ax=0,就是返回值,也就是⼦进程返回的pid为0的原因。
p->thread.ip = (unsigned long) ret_from_fork,前⾯设置了sp栈顶,这⾥再设置ip。
fork、父进程和子进程
fork、⽗进程和⼦进程进程什么是进程?进程是⼀个运⾏中的程序实体,拥有独⽴的堆栈、内存空间和逻辑控制流。
这是标准的进程概念。
让我们通过操作系统的fork函数看看这个抽象的概念是怎么在进程的实现中体现出来的。
构成要素创建⼀个进程,需要进程体、进程表和数据空间。
进程体在C代码中对应⼀个函数,编译成⼆进制代码后就是⼀组指令。
进程表⽤来记录进程的进程ID、进程名称、寄存器快照空间。
简单说,当中断发⽣时,会保存此刻CPU的状态,然后记录到进程表中。
进程表的作⽤就是⽤来存储进程快照。
进程堆栈的作⽤是什么?存储进程中函数的参数,存储进程运⾏过程中的局部数据。
数据空间呢?先看⼀段简单的代码。
char *f(int a, int b);int main(int argc, char **argv){f(5, 6);return 0;}char *f(int a, int b){int c = a + b;char *str = "Hello, World!";return str;}1. 两个参数a和b存储在进程的堆栈中。
2. 指针char *str指向的内存中的数据STR存储在进程的数据空间中。
为什么STR不是存储在进程的堆栈中呢?函数f的返回值是STR的内存地址。
执⾏这段代码,我们会发现:调⽤函数f能正确获得STR。
试想⼀下,假如STR存储在进程的堆栈中,当f执⾏结束后,堆栈中的数据会被清空,我们调⽤函数f是不能正确获得STR的。
STR存储在进程的数据空间中,存储在进程堆栈中的只是存储STR的内存空间的内存地址。
fork进程A调⽤fork新建进程B,A是B的⽗进程,B是A的⼦进程。
fork执⾏结束后,如果能成功创建B进程,B进程的数据空间、堆栈和进程表和A进程的这些要素完全相同。
差异B进程毕竟是不同于A进程的独⽴进程,所以:1. B进程的数据空间中的数据和A进程的数据空间的数据⼀致,但是,两个进程的数据空间却是不同的内存空间。
【Linux进程】fork函数详解
【Linux进程】fork函数详解⼀、fork⼊门知识⼀个进程,包括代码、数据和分配给进程的资源。
fork()函数通过系统调⽤创建⼀个与原来进程⼏乎完全相同的进程,也就是两个进程可以做完全相同的事,但如果初始参数或者传⼊的变量不同,两个进程也可以做不同的事。
⼀个进程调⽤fork()函数后,系统先给新的进程分配资源,例如存储数据和代码的空间。
然后把原来的进程的所有值都复制到新的新进程中,只有少数值与原来的进程的值不同。
相当于克隆了⼀个⾃⼰。
我们来看⼀个例⼦:#include <unistd.h>#include <stdio.h>int main (){pid_t fpid; //fpid表⽰fork函数返回的值int count=0;fpid=fork();if (fpid < 0)printf("error in fork!");else if (fpid == 0) {printf("i am the child process, my process id is %d/n",getpid());count++;}else {printf("i am the parent process, my process id is %d/n",getpid());count++;}printf("统计结果是: %d/n",count);return0;}运⾏结果是:i am the child process, my process id is 5574统计结果是: 1i am the parent process, my process id is 5573统计结果是: 1在语句fpid=fork()之前,只有⼀个进程在执⾏这段代码,但在这条语句之后,就变成两个进程在执⾏了,这两个进程的⼏乎完全相同,将要执⾏的下⼀条语句都是if(fpid<0)……为什么两个进程的fpid不同呢,这与fork函数的特性有关。
linux fork原理
linux fork原理Linux中的fork是一个非常重要的系统调用,它是Linux操作系统的核心功能之一。
在本文中,我们将探讨fork的原理、作用以及一些相关的概念。
让我们来了解一下fork的定义。
在Linux中,fork是一个系统调用,用于创建一个新的进程,该进程是调用进程的副本。
这个新创建的进程称为子进程,而调用fork的进程称为父进程。
fork的原理是通过复制父进程的内存空间来创建子进程。
当调用fork时,操作系统会为子进程分配一个新的进程ID,并复制父进程的内存空间。
这意味着子进程将具有与父进程相同的代码、数据和堆栈。
但是,子进程的内存空间是独立的,因此对于子进程而言,它在运行时是完全独立的。
fork的返回值在父进程和子进程中是不同的。
对于父进程,fork的返回值是子进程的进程ID,而对于子进程,返回值是0。
这样,通过检查fork的返回值,父进程和子进程可以采取不同的行动。
在fork之后,父进程和子进程是并发运行的。
这意味着它们可以同时执行不同的操作。
父进程可以继续执行其余的代码,而子进程可以执行其他与父进程不同的操作。
这种并发性是Linux中多任务处理的基础。
另一个重要的概念是父子进程间的通信。
由于父进程和子进程共享相同的内存空间,它们可以通过在内存中写入和读取数据来进行通信。
这种通信方式非常高效,因为它避免了进程间的上下文切换和系统调用的开销。
fork还支持进程的层次结构。
通过多次调用fork,一个进程可以创建多个子进程,而每个子进程又可以创建自己的子进程。
这样,就形成了一个进程树。
父子进程间的关系可以用树状结构来表示,父进程是子进程的祖先,而子进程是父进程的后代。
在实际应用中,fork经常与exec函数一起使用。
exec函数用于在子进程中执行一个新的程序,它可以替换子进程的代码和数据。
这样,子进程可以成为一个全新的进程,而不再是父进程的副本。
总结一下,Linux中的fork是一个重要的系统调用,用于创建子进程。
fork
自由及开放源代码软件可以从原有开发团队复刻而不需要事先的许可,这也不会违反任何著作权法律。授权 的专有软件(例如Unix)的复刻也时有发生。
介绍
子进程是父进程的副本,它将获得父进程数据空间、堆、栈等资源的副本。注意,子进程持有的是上述存储 空间的“副本”,这意味着父子进程间不共享这些存储空间。
UNIX将复制父进程的空间内容给子进程,因此,子进程有了独立的空间。在不同的UNIX (Like)系统下,我 们无法确定fork之后是子进程先运行还是父进程先运行,这依赖于系统的实现。所以在移植代码的时候我们不应 该对此作出任何的假设。
介绍
fork系统调用用于创建一个新进程,称为子进程,它与进程(称为系统调用fork的进程)同时运行,此进 程称为父进程。创建新的子进程后,两个进程将执行fork()系统调用之后的下一条指令。子进程使用相同的pc (程序计数器),相同的CPU寄存器,在父进程中使用的相同打开文件。
它不需要参数并返回一个整数值。下面是fork()返回的不同值。 负值:创建子进程失败。 零:返回到新创建的子进程。 正值:返回父进程或调用者。该值包含新创建的子进程的进程ID 。
分叉函数
分叉函数
头文件
函数原型
函数原型
pid_t fork( void); (pid_t是一个宏定义,其实质是int被定义在#includesys/types.h>中) 返回值:若成功调用一次则返回两个值,子进程返回0,父进程返回子进程ID;否则,出错返回-1
函数说明
函数说明
一个现有进程可以调用fork函数创建一个新进程。由fork创建的新进程被称为子进程(child process)。 fork函数被调用一次但返回两次。两次返回的唯一区别是子进程中返回0值而父进程中返回子进程ID。
fork函数作用
fork函数作用
fork函数是一种用于创建进程的函数,它可以在Unix系
统和类Unix系统上使用。
它允许一个进程(父进程)创建另
一个进程(子进程),它们都从原来的进程中派生出来。
这样,父进程和子进程就可以并行地执行任务,有效地利用多核
CPU的优势。
fork函数的基本原理是,当它被调用时,操作系统就会复
制当前进程,生成一个新的进程,新进程从原进程继承了代码,数据和上下文(如文件描述符)。
每个进程具有自己的进程号(PID),它们都可以同时运行,独立于其他进程。
fork函数可以用于多种目的,但最常见的用途是创建多个
子进程,用于完成多任务。
例如,一个程序可以使用fork函
数创建一个子进程,用于处理某些类型的任务,另一个子进程用于处理另外一种类型的任务。
这样,就可以将更多的任务分配到多核CPU上,提高系统性能。
另外,fork函数还可以用于创建守护进程。
守护进程是一
种特殊的进程,它不属于当前登录用户,而是属于根用户。
它不断地运行,监控系统的状态,在系统发生故障时自动重启系统。
守护进程的创建通常是通过fork函数完成的。
此外,fork函数还可以用于创建shell程序。
shell程序是
一种特殊的程序,它可以从shell脚本中接受命令,并将命令
转换为系统调用,最终在系统上执行命令。
shell程序也是通过fork函数创建的。
总之,fork函数是一种重要的函数,它可以用于创建新的进程,完成多任务处理,创建守护进程和shell程序等。
它可以极大地提高系统的性能,是多核CPU上编程的重要工具。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
waitpid
监视子进程退出
重启子进程
习题
int main() { for(i=0;i<4;i++) fork(); while(1)sleep(1); }
• 4、画出进程树。
• 5、画出进程树。
• 6、画出进程树。
• 7、以下程序的功能是?
进程基本属性 -
进程号(PID)
并行与并发的区别
父进程号(PPID)
创建进程
• fork fork函数调用成功后,其子进程会复制父进 程的几乎所有信息(除PID等信息).
8671
8672
请分析以下程序的进程树
再请分析以下程序的进程树
继续分析以下程序的进程树
请大家画出进程树?
再看看for语句
• 以下程序运行后父子进程的个数,以及进 程数?。
Ps -aux
• 产生了2*2*2=8个进程 • 如果是for(i=0;i<4;i++)fork();将产生2的4次 方=16个进程。画出进程树。
ps -ef
9000
9001
9002
9003
9005
9006
9004
9007
如图,则情况如何
• 8、以下程序的功能是?
9192
9193
9194
9195
如图,又如何
9247
9248
9249
9250
退出进程
• 可以通过以下方式结束进程。
– 向exit或_exit发布一个调用。 – 在main函数中执行return。 – 隐含的离开main函数。
等待进程结束
• 调用wait()函数的父亲进程将等待该进程的 任意一个子进程结束后才继续执行(如果 有多个子进程,只需要等待其中的一个进 程)。