fork函数详解

合集下载

fork函数实例

fork函数实例

fork函数实例fork函数是操作系统中一个非常重要的函数,它的作用是创建一个新的进程。

在本文中,我们将详细介绍fork函数的使用方法和原理。

一、fork函数的使用方法在C语言中,fork函数的原型如下:```c#include <sys/types.h>#include <unistd.h>pid_t fork(void);```调用fork函数会创建一个新的进程,这个新进程是调用进程的一个副本。

新进程与调用进程几乎完全相同,包括代码、数据和打开的文件等。

fork函数的返回值有以下三种情况:- 若返回值为-1,表示fork函数调用失败,新进程创建失败;- 若返回值为0,表示当前进程为新创建的子进程;- 若返回值大于0,表示当前进程为父进程,返回值为子进程的进程ID。

我们可以根据fork函数的返回值来判断当前进程是父进程还是子进程,并相应地对它们进行不同的处理。

下面是一个简单的示例代码:```c#include <stdio.h>#include <unistd.h>int main() {pid_t pid = fork();if (pid < 0) {printf("fork error");} else if (pid == 0) {printf("This is child process. PID: %d\n", getpid());} else {printf("This is parent process. PID: %d, Child PID: %d\n", getpid(), pid);}return 0;}```运行上述代码,可以看到输出结果中会有两行信息,分别表示父进程和子进程的相关信息。

二、fork函数的原理fork函数的原理是通过创建一个与当前进程几乎完全相同的新进程来实现的。

fork函数超详解及其用法

fork函数超详解及其用法

3. 进程控制上一页第30 章进程下一页3. 进程控制3.1. fork函数#include <sys/types.h>#include <unistd.h>pid_t fork(void);fork调用失败则返回-1,调用成功的返回值见下面的解释。

我们通过一个例子来理解fork是怎样创建新进程的。

例30.3. fork#include <sys/types.h>#include <unistd.h>#include <stdio.h>#include <stdlib.h>int main(void){pid_t pid;char *message;int n;pid = fork();if (pid < 0) {perror("fork failed");exit(1);}if (pid == 0) {message = "This is the child\n"; n = 6;} else {message = "This is the parent\n"; n = 3;}for(; n > 0; n--) {printf(message);sleep(1);}return 0;}$ ./a.outThis is the childThis is the parentThis is the childThis is the parentThis is the childThis is the parentThis is the child$ This is the childThis is the child这个程序的运行过程如下图所示。

图30.4. fork父进程初始化。

父进程调用fork,这是一个系统调用,因此进入内核。

内核根据父进程复制出一个子进程,父进程和子进程的PCB信息相同,用户态代码和数据也相同。

linux操作系统下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函数

父进程
父进程
#include <sys/types.h> main() 执 { 行 pid_t val; printf(“PID…); 分裂 val=fork(); if(val!=0) printf(“parent…”); else printf(“child…); }
main( ) { pid_t val; printf(“PID…); val=fork(); if(val!=0) printf(“parent…”); else printf(“child…); }
运行结果1 global=5,vari=4;
global=4,vari=5;
运行结果2
global=4,vari=5; global=5,vari=4
分析:子进程和父进程的数据段、堆栈段不同。子进程执 行语句“global++,vari—”时,只是对自己的数据段 进行了修改,并未影响到父进程的数据段,
exec()—执行一个文件的调用

子进程如何执行一个新的程序文本?
通过exec()调用族,加载新的程序文本
通过一个系统调用exec,子进程可以拥有自己的可 执行代码。即exec用一个新进程覆盖调用进程。 它的参数包括新进程对应的文件和命令行参数。成 功调用时,不再返回;否则,返回出错原因。 六种exec调用格式:各种调用的区别在于参数的处 理方法不同,常用的格式有:
void main(void) { printf(“Hello \n”); fork(); printf(“Bye \n”); }
运行结果 Hello Bye Bye
fork()调用例子(2)
#include<stdio.h> #Include<sys/types.h> #include<unistd.h> void main(void){ if (fork()==0) printf(“In the CHILD process\n”); else printf(“In the PARENT process\n”); }

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函数详解1.函数原型:```c#include <sys/types.h>#include <unistd.h>pid_t fork(void);```在父进程中,fork函数返回新创建的子进程的PID;在子进程中,fork函数返回0。

如果fork函数调用失败,则返回-12.函数功能:fork函数将调用它的进程(父进程)复制一份,并创建一个新的进程(子进程)。

这两个进程几乎是完全相同的,只有PID不同。

父进程中的所有资源(内存、文件描述符等)都会被复制到子进程中,子进程开始执行的位置是从fork函数返回的点开始的。

3.函数用法:fork函数的用法非常简单。

在程序中调用fork函数时,会创建一个新的子进程。

之后,父进程和子进程会并行执行,但是它们执行的顺序是不确定的。

父进程和子进程中的代码是完全独立的,它们可以有不同的数据,走不同的分支,执行不同的操作。

4.函数执行结果:- 如果fork函数返回值大于0,说明调用成功且处于父进程中。

此时返回的值就是新创建的子进程的PID。

- 如果fork函数返回值等于0,说明处于子进程中。

- 如果fork函数返回值小于0,说明调用失败。

5.函数使用注意事项:- fork函数并不是真正的复制,而是通过写时复制(copy-on-write)技术进行优化。

在fork函数调用时,父进程和子进程共享相同的物理内存块,只有在其中一个进程试图修改内存时才会进行复制。

- fork函数会复制父进程的打开文件描述符。

但是,需要注意的是,父进程和子进程会共享文件的偏移量,读写文件时应该注意这个问题。

- fork函数之后,子进程会继承父进程的信号处理程序和文件锁,并且会共享父进程的信号处理程序和文件锁状态。

6.参数类型:- pid_t:是进程的ID,它是一个无符号整数类型,被定义在sys/types.h中。

7.函数调用示例:```c#include <stdio.h>#include <unistd.h>int main(void)pid_t pid;int x = 1;pid = fork(;if (pid == 0)printf("Child process: x = %d\n", ++x);} elseprintf("Parent process: x = %d\n", --x);}```上述示例中,首先声明了一个pid_t类型的变量pid和一个整型变量x。

对fork函数的理解

对fork函数的理解

对fork函数的理解前言:对于刚刚接触Unix/Linux操作系统,在Linux下编写多进程的人来说,fork 是最难理解的概念之一:它执行一次却返回两个值。

因此,本文着重从以下几个方面来使初学者加深对fork函数的理解和应用:fork函数的机制与特性、fork 函数的两次返回和父子进程的执行顺序介绍、关键字:fork函数、返回值、父进程、子进程正文:一、fork函数的机制与特性1 #include<stdio.h>2 #include<unistd.h>3 #include<stdlib.h>45 int main(void)6 {7 pid_t pid;8 if ((pid = fork()) == 00) {9 getchar();10 exit(0);11 }12 getchar ();13}14父进程成功的调用fork(8行)后将会产生一个子进程。

此时会有两个问题:1、子进程的代码从哪里来?2、子进程首次被OS调用时,执行的第一条代码是哪条代码?子进程的代码是父进程代码的一个完全相同拷贝。

事实上不仅仅是text 段,子进程中的全部进程空间都是(包括:text/data/bss/heap/commandline/envir onment)父进程空间的一个完全拷贝。

下一个问题是谁为子进程分配了内存空间?谁复制了父进程空间的内容到子空间?fork当仁不让。

事实上,fork 实现的源代码,由四部分组成:首先,为子进程分配内存空间;然后,将父进程空间的全部内容复制到分配给子进程的内存空间;接着在内核数据结构中创建并正确初始化子进程的PCB (包括两个重要信息:子进程pid,PC 的值=善后代码的第一条指令地址);最后是一段善后代码。

由于子进程的PCB已经产生,因此子进程可以被OS调度子进程首次被OS调度时,执行的第一条代码在fork 内部,不过从引用程序的角度来看,子进程首次被OS调度时,执行的第一条代码是从fork返回。

fork()函数的理解

fork()函数的理解

对于刚刚接触Unix/Linux操作系统,在Linux下编写多进程的人来说,fork是最难理解的概念之一:它执行一次却返回两个值。

首先我们来看下fork函数的原型:#i nclude <sys/types.h>#i nclude <uni ST d.h>pid_t fork(void);返回值:负数:如果出错,则fork()返回-1,此时没有创建新的进程。

最初的进程仍然运行。

零:在子进程中,fork()返回0正数:在负进程中,fork()返回正的子进程的PID其次我们来看下如何利用fork创建子进程。

创建子进程的样板代码如下所示:pid_t child;if((child = fork())<0)/*错误处理*/else if(child == 0)/*这是新进程*/else/*这是最初的父进程*/fock函数调用一次却返回两次;向父进程返回子进程的ID,向子进程中返回0,这是因为父进程可能存在很多过子进程,所以必须通过这个返回的子进程ID来跟踪子进程,而子进程只有一个父进程,他的ID可以通过getppid取得。

下面我们来对比一下两个例子:第一个:#include <unistd.h>#include <stdio.h>int main(){pid_t pid;int count=0;pid = fork();printf( "This is first time, pid = %d\n", pid );printf( "This is sec ON d time, pid = %d\n", pid );count++;printf( "count = %d\n", count );if ( pid>0 ){printf( "This is the parent process,the child has the pid:%d\n", pid );}else if ( !pid ){printf( "This is the child Process.\n")}else{printf( "fork failed.\n" );}printf( "This is third time, pid = %d\n", pid );printf( "This is fouth time, pid = %d\n", pid );return 0;}运行结果如下:问题:这个结果很奇怪了,为什么printf的语句执行两次,而那句“count++;”的语句却只执行了一次接着看:#include <unistd.h>#include <stdio.h>int main(void){pid_t pid;int count=0;pid = fork();printf( "Now, the pid returned by calling fork() is %d\n", pid );if ( pid>0 ){printf( "This is the parent proc ESS,the child has the pid:%d\n", pid );printf( "In the parent process,count = %d\n", count );}else if ( !pid ){printf( "This is the child process.\n");printf( "Do your own things here.\n" );count ++;printf( "In the child process, count = %d\n", count );}else{printf( "fork failed.\n" );}return 0;}运行结果如下:现在来解释上面提出的问题。

fork函数返回值浅谈

fork函数返回值浅谈

fork函数返回值浅谈fork函数返回值浅谈 fork简介 fork英文原意是分岔分支的意思而在操作系统中乃是著名的Unix或类Unix如LinuxMinix中用于创建子进程的系统调用。

【NOTE1】 fork的作用是什么换句话说你用fork的目的是什么――是为了产生一个新的进程地球人都知道产生一个什么样的进程――和你本来调用fork的那个进程基本一样的进程其实就是你原来进程的副本真的完全一样吗――当然不能完全一样你要两个除了pid之外其它一模一样的进程干什么就算memory 再多也不用这么摆谱吧哪里不一样――当然最重要的是fork之后执行的代码不一样you knowi know 怎么实现呢――如果是Windows它会让你在fork里面提供一大堆东西指明这个那个什么的… 我用的是unix啊――所以很简单unix会让两个进程不错原来是一个unix替你复制了一个现在有两个在fork之后产生不同返回值不同。

其中一个进程使用新的pid里面的fork返回零这个进程就是子进程而另一个进程使用原来的pid中的fork返回前面那个子进程的 pid他自己被称为父进程然后呢――写代码的人又不笨当然就根据返回值是否非零来判断了现在我是在子进程里面呢还是在父进程里面在子进程里面就执行子进程该执行的代码在父进程里面就执行父进程的代码… 有铁杆windows fans借此说明windows好啊子进程用子进程的代码父进程用父进程的你unix笨了吧子进程包含父进程、子进程的代码父进程包含父进程子进程的代码岂不是多占用内存了吗――据我所知unix代码段都是可重入代码也就是说进程复制并不复制代码段若干个进程共享同一代码段增加的只是全局共享数据和对文件描述符的引用等另外就是堆栈。

你一个代码长达10M的进程fork出三四个子进程只是增加一点内存占用如果你没有使用很多全局变量的话而不是占用40M以上的内存。

【NOTE2】程序从fork开始分支称分支不准确一路是主进程pid 0pid是子进程ID一路是子进程pid0自此分成两个任务其实fork的时候已经两个分支了数据段被复制了一份因此pid有两份执行pidfork时返回值赋给pid在两个进程中运行 fork会返回给父进程的那个0的值告诉调用者新建进程的pid 子进程的fork返回值是0 更不用说if.else的比较也是在两个进程中都做的了【NOTE3】 fork的精辟剖析程序如下 include unistd.h include sys/types.h main pid_t pid pidfork ifpid 0printferror in fork else ifpid0printfi am the child processmy process id isdngetpid else printfi am the parent processmyprocess id isdngetpid 结果是 rootlocalhost c./a.out iam the child processmy process idis 4286 iam the parent processmy process id is 4285 一要搞清楚fork 的执行过程就必须先讲清楚操作系统中的进程process概念。

fork函数 用法

fork函数 用法

fork函数用法**标题:fork函数用法详解****一、概述**fork函数是Unix/Linux操作系统中常用的系统调用之一,它用于创建一个新的进程,并返回新进程的进程ID。

这个函数是在调用进程中创建新进程的基础,可以在当前进程的基础上,生成一个新的子进程,父进程和子进程之间可以共享一些数据,但是也必须考虑并发环境中的安全问题。

**二、函数原型**在Unix/Linux系统中,fork函数的基本原型为:intfork(void)。

这个函数会在调用它的进程中创建一个新的进程,并返回两个值:新创建的子进程的进程ID和父进程的进程ID。

如果返回值为-1,则表示fork函数调用失败。

**三、使用场景**fork函数主要用于创建一个新的进程,该进程继承了父进程的环境和状态。

在多线程或多进程编程中,fork函数可以帮助我们更好地管理并发环境中的资源。

例如,在父进程中创建一个新的子进程来执行一些特定的任务,子进程可以继承父进程的一些资源(如打开的文件描述符),而父进程则可以继续执行其他任务。

**四、注意事项**在使用fork函数时,需要注意以下几点:1. fork函数会创建一个新的进程,并返回两个值。

因此,需要确保在调用fork函数之前已经正确地分配了足够的内存空间来保存返回的两个值。

2. fork函数创建的新进程与原进程共享一些资源(如打开的文件描述符),但也需要注意并发环境中的安全问题。

例如,需要确保在子进程中关闭父进程打开的文件描述符,以避免资源泄漏。

3. 在子进程中执行一些操作时,需要考虑到父进程的状态和环境。

例如,如果父进程正在等待某个条件成立(如某个文件被修改),则需要考虑到子进程是否会改变这个条件。

4. fork函数在创建新进程时,会复制一部分父进程的内存空间到新的子进程中。

因此,如果父进程的内存空间非常大,则创建子进程所消耗的时间和内存也会相应增加。

**五、示例代码**下面是一个简单的示例代码,展示了fork函数的使用方法:```c#include <stdio.h>#include <unistd.h>#include <sys/types.h>int main() {pid_t pid; // 用于保存新创建的子进程的进程ID// 调用fork函数创建新进程pid = fork();// 判断fork函数是否成功if (pid < 0) {printf("Fork failed!\n");return 1;} else if (pid == 0) { // 子进程结束循环执行完毕后返回0,否则返回-1结束程序运行// 子进程代码段...while(1) { // 循环执行一些任务...} } else { // 父进程代码段...} // 父进程继续执行其他任务...}```六、总结**fork函数是Unix/Linux系统中的一个重要系统调用,用于在调用进程中创建一个新的子进程。

fork函数的2个返回值说明

fork函数的2个返回值说明

fork简介:fork英文原意是“分岔,分支”的意思,而在操作系统中,乃是著名的Unix(或类Unix,如Linux,Minix)中用于创建子进程的系统调用。

【NOTE1】fork () 的作用是什么?换句话说,你用fork () 的目的是什么?――是为了产生一个新的进程,地球人都知道:)产生一个什么样的进程?――和你本来调用fork () 的那个进程基本一样的进程,其实就是你原来进程的副本;真的完全一样吗?――当然不能完全一样,你要两个除了pid 之外其它一模一样的进程干什么,就算memory 再多也不用这么摆谱吧?哪里不一样?――当然最重要的是fork () 之后执行的代码不一样,you know, i know :)怎么实现呢?――如果是Windows,它会让你在fork () 里面提供一大堆东西,指明这个那个什么的…… 我用的是unix 啊――所以很简单,unix 会让两个进程(不错,原来是一个,unix 替你复制了一个,现在有两个)在fork () 之后产生不同:返回值不同。

其中一个进程(使用新的pid)里面的fork () 返回零,这个进程就是“子进程”;而另一个进程(使用原来的pid)中的fork () 返回前面那个子进程的pid,他自己被称为“父进程”然后呢?――写代码的人又不笨,当然就根据返回值是否非零来判断了,现在我是在子进程里面呢,还是在父进程里面?在子进程里面就执行子进程该执行的代码,在父进程里面就执行父进程的代码……有铁杆windows fans 借此说明,windows 好啊,子进程用子进程的代码,父进程用父进程的,你unix 笨了吧,子进程包含父进程、子进程的代码,父进程包含父进程子进程的代码,岂不是多占用内存了吗?――据我所知,unix 代码段都是可重入代码,也就是说,进程复制,并不复制代码段,若干个进程共享同一代码段,增加的只是全局共享数据和对文件描述符的引用等,另外就是堆栈。

fork

fork
1)fork()系统调用是创建一个新进程的首选方式,fork的返回值要么是0,要么是非0,父进程与子进程的根本区别在于fork函数的返回值.
2)vfork()系统调用除了能保证用户空间内存不会被复制之外,它与fork几乎是完全相同的.vfork存在的问题是它要求子进程立即调用exec,
而不用修改任何内存,这在真正实现的时候要困难的多,尤其是考虑到exec调用有可能失败.
./test
count= 1
count= 1
Segmentation fault (core dumped)
分析:
通过将fork()换成vfork(),由于vfork()是共享数据段,为什么结果不是2呢,答案是:
vfork保证子进程先运行,在它调用 exec 或 exit 之后父进程才可能被调度运行.如果在调用这两个函数之前子进程依赖于父进程的进一步动作,则会导致死锁.
示例代码:
#include <unistd.h>
#include <stdio.h>
int main(int argc, char ** argv )
{
int pid = fork();
if(pid == -1 )
{
// print("error!");
} else if( pid = =0 ) {
3)做最后的修改,在子进程执行时,调用_exit(),程序如下:
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
int main(void)

C语言fork函数解析

C语言fork函数解析

首先看下fork的基本知识:函数原型:pid_t fork( void);返回值:若成功调用一次则返回两个值,子进程返回0,父进程返回子进程ID;否则,出错返回-1一个现有进程可以调用fork函数创建一个新进程。

由fork创建的新进程被称为子进程(child process)。

fork函数被调用一次但返回两次。

两次返回的唯一区别是子进程中返回0值而父进程中返回子进程ID。

注意要点:1、子进程是父进程的副本,它将获得父进程数据空间、堆、栈等资源的副本。

此处先简要介绍下COW(Copy-on-write)机制,大致原理如下:在复制一个对象的时候并不是真正的把原先的对象复制到内存的另外一个位置上,而是在新对象的内存映射表中设置一个指针,指向源对象的位置,并把那块内存的Copy-On-Write位设置为1.这样,在对新的对象执行读操作的时候,内存数据不发生任何变动,直接执行读操作;而在对新的对象执行写操作时,将真正的对象复制到新的内存地址中,并修改新对象的内存映射表指向这个新的位置,并在新的内存位置上执行写操作。

linux内核下fork使用COW机制工作原理:进程0(父进程)创建进程1(子进程)后,进程0和进程1同时使用着共享代码区内相同的代码和数据内存页面, 只是执行代码不在一处,因此他们也同时使用着相同的用户堆栈区。

在为进程1(子进程)复制其父进程(进程0)的页目录和页表项时,进程0的640KB页表项的属性没有改动过(仍然可读写),但是进程1的640KB对应的页表项却被设置成只读。

因此当进程1(子进程)开始执行时,对用户堆栈的入栈操作将导致页面写保护异常,从而使得内核的内存管理程序为进程1在主内存区中分配一内存页面,并把进程0中的页面内容复制到新的页面上。

从此时开始,进程1开始有自己独立的内存页面,由于此时的内存页面在主内存区,因此进程1中继续创建新的子进程时也可以采用COW技术。

内核调度进程运行时次序是随机的,进程0创建进程1后,可能先于进程1修改共享区,进程0是可读写的,在未分开前,进程1是只读的,由于两个进程共享内存空间,为了不出现冲突问题,就必须要求进程0在进程1执行堆栈操作(进程1的堆栈操作会导致页面保护异常,从而使得进程1在主内存区得到新的用户页面区,此时进程1和进程0才算是真正独立,如前面所述)之前禁止使用用户堆栈区。

f o r k ( ) 介 绍 ( 2 0 2 0 )

f o r k ( ) 介 绍 ( 2 0 2 0 )

fork函数与vfork函数的区别与联系详解创建一【导师实操追-女教-程】个新进程的方法只有由某个已存在的进程调用fork()或vfork(),当然某些进程如init等是作为系统启动的一部分【Q】而被内核创建的。

1.f【1】ork函数介绍#in【0】clude?#inc【⒈】lude?pid【6】_t fork (void );正确返回【9】:父进程中返回子进程的进程号;子进程中返回0;(单调用双返【5】回函数)错误返回【2】:-1;子进程是【б】父进程的一个拷贝。

具体说,子进程从父进程那得到了数据段和堆栈段,但不是与父进程共享而是单独分配内存。

fork函数返回后,子进程和父进程都是从fork函数的下一条语句开始执行。

由于子进程与父进程的运行是无关的,父进程可先于子进程运行,子进程也可先于父进程运行,所以下段程序可以有两种运行结果。

[root@happy src]# cat simplefork.c#include?#include?#includeint globa = 4;int main (void )pid_t pid;int vari = 5;printf ("before fork" );if ((pid = fork()) 0){printf ("fork error");exit (0);else if (pid == 0){globa++ ;printf("Child changed");printf("Parent did not changde");printf("globa = %d vari = %d",globa,vari); exit(0);运行结果:(可能出现的一种结果)[root@happy src]# .-a.outbefore forkChild changedgloba = 5 vari = 4Parent did not changdegloba = 4 vari = 52.vfork函数介绍vfork创建新进程的主要目的在于用exec函数执行另外的程序,实际上,在没调用exec或exit之前子进程的运行中是与父进程共享数据段的。

c语言fork函数

c语言fork函数

c语言fork函数fork函数是Unix和类Unix操作系统中的一个系统调用函数,用于创建一个新的进程。

在调用fork函数时,操作系统会为当前进程创建一个副本,生成一个新的进程,即子进程。

子进程和父进程拥有相同的代码、数据和堆栈段,但是拥有独立的进程ID,并且子进程的PID与父进程不同,子进程的PPID为父进程的PID。

下面将通过四个方面详细介绍fork函数的使用和相关注意事项。

一、fork函数的原型和返回值```#include <sys/types.h>#include <unistd.h>pid_t fork(void);```fork函数没有参数,返回值为pid_t类型,它代表进程的ID。

在父进程中,fork函数返回子进程的PID;而在子进程中,fork函数返回0。

如果创建子进程时出现错误,fork函数返回一个负数,代表错误的类型。

二、父进程和子进程的代码段在调用fork函数之后,操作系统会将父进程的整个代码段、数据段和堆栈段复制到子进程中。

这也意味着,父进程和子进程会从fork函数之后的那一行代码开始执行。

所以,在调用fork函数之前,应该通过其中一种方式使父进程和子进程的执行路径不同,以免它们会执行相同的代码。

三、父进程和子进程共用的文件描述符在fork函数调用之后,父进程和子进程共用相同的文件描述符。

这个特性对于父子进程之间的通信非常方便。

当父子进程中的一个进程读取或写入了共享的文件描述符时,假设是读取操作,它会将文件的读取位置记录在文件描述符对应的数据结构中。

另一个进程也会使用相同的文件描述符操作同一个文件,并且它会从上一个进程读取的位置开始。

这样,父进程和子进程之间就可以通过读取和修改文件描述符来进行相互通信。

四、子进程的退出状态在子进程执行完毕后,它会以存在两种情况:一种是正常终止,一种是异常终止。

1. 正常终止:子进程可以通过调用exit(函数或者从main函数中返回来正常终止。

fork()函数总结

fork()函数总结

printf("n=[%d]\n", n++); return 0; }
这个例子在linux下用gcc编译,运行结果如下:
fork! [child]i am child! [child]getpid=[7422] [child]pid=[0] n=[0] [parent]i am parent! [parent]getpid=[7421] [parent]pid=[7422] n=[0]
表,该文件表是由内核维护的,两个进程共享文件状态,偏移量等。这一点很重要,当在父进程中关闭文件时,子进程的文件描述符仍然
有用,相应的文件表也不会被释放。(3)为了提高效率,fork后并不立即复制父进程空间,采用了COW (Copy -On-W rite);当父子进程
任意之一,要修改数据段、堆、栈时,进行复制操作,但仅复制修改区域;)。父子进程间共享的存储空间只有代码段(只读的,且仅共
享fork()后面的代码段)。子进程和父进程继续执行fork调用之后的指令。(4)fork之后,这两个进程执行没有固定的先后顺序,哪个进程先
执行要看系lude <SYS types.h> #include <UNISTD.H> #include <STDIO.H> int main() { pid_t pid; static int n = 0; printf("fork!\n"); switch (pid = fork()) { case -1: { /* ..pid.-1.fork.... */ /* ........ */ /* .......... */ perror("The fork failed!"); break; } case 0: { /* pid.0.... */ printf("[child]i am child!\n"); printf("[child]getpid=[%d]\n", getpid() ); printf("[child]pid=[%d]\n", pid ); break; } default: { /* pid..0.... */ printf("[parent]i am parent!\n" ); printf("[parent]getpid=[%d]\n",getpid() ); printf("[parent]pid=[%d]\n",pid ); break; } }

Fork函数

Fork函数

Fork函数计算机程序设计中的分叉函数。

一个进程,包括代码、数据和分配给进程的资源。

fork()函数通过系统调用创建一个与原来进程几乎完全相同的进程,也就是两个进程可以做完全相同的事,但如果初始参数或者传入的变量不同,两个进程也可以做不同的事。

进程调用fork()函数后,系统先给新的进程分配资源,例如存储数据和代码的空间。

然后把原来的进程的所有值都复制到新的新进程中,只有少数值与原来的进程的值不同。

相当于克隆了一个自己。

返回值:若成功调用一次则返回两个值,子进程返回0,父进程返回子进程标记;否则,出错返回-1一个现有进程可以调用fork函数创建一个新进程。

由fork创建的新进程被称为子进程(child process)。

fork函数被调用一次但返回两次。

两次返回的唯一区别是子进程中返回0值而父进程中返回子进程ID。

子进程是父进程的副本,它将获得父进程数据空间、堆、栈等资源的副本。

注意,子进程持有的是上述存储空间的“副本”,这意味着父子进程间不共享这些存储空间。

UNIX将复制父进程的地址空间内容给子进程,因此,子进程有了独立的地址空间。

在不同的UNIX (Like)系统下,我们无法确定fork之后是子进程先运行还是父进程先运行,这依赖于系统的实现。

所以在移植代码的时候我们不应该对此作出任何的假设。

一个进程调用fork()函数后,系统先给新的进程分配资源,例如存储数据和代码的空间。

然后把原来的进程的所有值都复制到新的新进程中,只有少数值与原来的进程的值不同。

相当于克隆了一个自己。

我们来看一个例子: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());printf("我是爹的儿子/n");//对某些人来说中文看着更直白。

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() 函数时需要仔细考虑程序的逻辑和安全性。

c语言fork函数

c语言fork函数

c语言fork函数
fork函数是C语言提供的一个重要系统调用,能够使用父进程的内存,数据和环境变量复制它的子进程,使该子进程继续运行,是Unix内核下进程间通信的基础。

它允许调用者完全复制自身以及自身的资源,得到一个新的进程。

fork函数在多个进程间共享数据很有必要,因为不同进程间各自拥有独立的内存空间,所以需要调用函数来实现多个进程间的数据共享,fork函数就是这样一个函数,它可以创建一个新的子进程复制父进程的环境变量和原有资源,协调多个子进程之间的数据通信,发挥重要的作用。

fork函数包含2个参数,一个是函数指针,用于指明函数时调用,该参数在创建子进程时传递给子进程;另一个参数是一个空指针,该指针可以指向一个存在的数据结构,进一步传递给子进程。

它具有有特殊的返回值,在父进程中,返回值为子进程的进程号,子进程中,返回值一般为0,如果函数调用失败,则返回-1。

fork函数实现了新创建的子进程会拷贝父进程的空间,并从fork调用的地方开始继续调用,它的实现是创建新的复制体,即使用新的进程描述符,把新复制体的PC,此时正在运行的进程的PC设置为fork调用的地址处。

此外,它还会把所有的新数据复制到新的进程中,但不包括新的地址空间(临时堆栈)被建立,以及即使是共享的段中被建立。

fork函数在很多地方都有重要作用,进程模型压缩利用它来创建多个进程,在Web服务器中,用它来生成servlet和JSP程序,另外,在系统调试上也有很大的用处。

总的来说,fork会使用父进程的环境创建一个子进程,它可以复制父进程的内存,数据和环境变量,并且在多个进程间共享数据上很有用,在C语言中有重要的地位。

函数fork与vfork的区别与联系详解

函数fork与vfork的区别与联系详解

创建一个新进程的方法只有由某个已存在的进程调用fork()或vfork(),当然某些进程如init等是作为系统启动的一部风而被内核创建的。

1.fork函数介绍#include sys/types.h>#include unistd.h>pid_t fork (void );正确返回:父进程中返回子进程的进程号;子进程中返回0;(单调用双返回函数)错误返回:-1;子进程是父进程的一个拷贝。

具体说,子进程从父进程那得到了数据段和堆栈段,但不是与父进程共享而是单独分配内存。

fork函数返回后,子进程和父进程都是从fork函数的下一条语句开始执行。

由于子进程与父进程的运行是无关的,父进程可先于子进程运行,子进程也可先于父进程运行,所以下段程序可以有两种运行结果。

[root@happy src]# cat simplefork.c#include stdio.h>#include sys/types.h>#include unistd.h>int globa = 4;int main (void ){pid_t pid;int vari = 5;printf ("before fork\n" );if ((pid = fork()) 0){printf ("fork error\n");exit (0);}else if (pid == 0){globa++ ;vari--;printf("Child changed\n");}elseprintf("Parent did not changde\n");printf("globa = %d vari = %d\n",globa,vari);exit(0);}运行结果:(可能出现的一种结果)[root@happy src]# ./a.outbefore forkChild changedgloba = 5 vari = 4Parent did not changdegloba = 4 vari = 52.vfork函数介绍vfork创建新进程的主要目的在于用exec函数执行另外的程序,实际上,在没调用exec 或exit之前子进程的运行中是与父进程共享数据段的。

  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
一、fork入门知识
一个进程,包括代码、数据和分配给进程的资源。fork()函数通过系统调用创建一个与原来进程几乎完全相同的进程,也就是两个进程可以做完全相同的事,但如果初始参数或者传入的变量不同,两个进程也可以做不同的事。
一个进程调用fork()函数后,系统先给新的进程分配资源,例如存储数据和代码的空间。然后把原来的进程的所有值都复制到新的新进程中,只有少数值与原来的进程的值不同。相当于克隆了一个自己。
for(i=0;i<2;i++){
pid_t fpid=fork();//执行完毕,i=0,fpid=0
if(fpid==0)
printf("%d child %4d %4d %4d\n",i,getppid(),getpid(),fpid);
else
printf("%d parent %4d %4d %4d\n",i,getppid(),getpid(),fpid);
为什么两个进程的fpid不同呢,这与fork函数的特性有关。fork调用的一个奇妙之处就是它仅仅被调用一次,却能够返回两次,它可能有三种不同的返回值:
1)在父进程中,fork返回新创建子进程的进程ID;
2)在子进程中,fork返回0;
3)如果出现错误,fork返回一个负值;
在fork函数执行完毕后,如果创建新进程成功,则出现两个进程,一个是子进程,一个是父进程。在子进程中,fork函数返回0,在父进程中,fork返回新创建子进程的进程ID。我们可以通过fork返回的值来判断当前进程是子进程还是父进程。
1 parent 3224 3225 3227
1 child 1 3227 0
1 child 1 3226 0
这份代码比较有意思,我们来认真分析一下:
第一步:在父进程中,指令执行到for循环中,i=0,接着执行fork,fork执行完后,系统中出现两个进程,分别是p3224和p3225(后面我都用pxxxx表示进程id为xxxx的进程)。可以看到父进程p3224的父进程是p2043,子进程p3225的父进程正好是p3224。我们用一个链表来表示这个关系:
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");//对某些人来说中文看着更直白。
对于子进程p3225,执行完第一次循环后,i=1,接着执行fork,系统中新增一个进程p3227,对于此进程,p3224->p3225(当前进程)->p3227(被创建的子进程)。从输出可以看到p3225原来是p3224的子进程,现在变成p3227的父进程。父子是相对的,这个大家应该容易理解。只要当前进程执行了fork,该进程就变成了父进程了,就打印出了parent。
i am the child process, my process id is 5574
我是爹的儿子
统计结果是: 1
i am the parent process, my process id is 5573
我是孩子他爹
统计结果是: 1
在语句fpid=fork()之前,只有一个进程在执行这段代码,但在这条语句之后,就变成两个进程在执行了,这两个进程的几乎完全相同,将要执行的下一条语句都是if(fpid<0)……
count++;
}
else {
printf("i am the parent process, my process id is %d\n",getpid());
printf("我是孩子他爹\n");
count++;
}
printf("统计结果是: %d\n",count);
return 0;
}
运行结果是:
所以打印出结果是:
1 parent 2043 3224 3226
1 parent 3224 3225 3227
第三步:第二步创建了两个进程p3226,p3227,这两个进程执行完printf函数后就结束了,因为这两个进程无法进入第三次循环,无法fork,该执行return 0;了,其他进程也是如此。
还有人可能疑惑为什么不是从#include处开始复制代码的,这是因为fork是把进程当前的情况拷贝一份,执行fork时,进程已经执行完了int count=0;fork只拷贝下一个要执行的代码到新的进程。
二、fork进阶知识
先看一份代码:
view plaincopy to clipboardprint?
04. printf("%d child %4d %4d %4d\n",i,getppid(),getpid(),fpid);
05. else
06. printf("%d parent %4d %4d %4d\n",i,getppid(),getpid(),fpid);
07.}
08.return 0;
}
return 0;
p3225(子进程)的变量为i=0,fpid=0(fork函数在子进程中返回0),代码内容为:
view plaincopy to clipboardprint?
01.for(i=0;i<2;i++){
02. pid_t fpid=fork();//执行完毕,i=0,fpid=0
03. if(fpid==0)
22. }
23. return 0;
24.}
/*
* fork_test.c
* version 2
* Created on: 2010-5-29
* Author: wangth
*/
#include <unistd.h>
#include <stdio.h>
int main(void)
{
int i=0;
printf("i son/pa ppid pid fpid\n");
//ppid指当前进程的父进程pid
//pid指当前进程的pid,
//fpid指fork返回给当前进程的值
for(i=0;i<2;i++){
pid_t fpid=fork();
if(fpid==0)
printf("%d child %4d %4d %4d\n",i,getppid(),getpid(),fpid);
03. if(fpid==0)
04. printf("%d child %4d %4d %4d\n",i,getppid(),getpid(),fpid);
05. else
06. printf("%d parent %4d %4d %4d\n",i,getppid(),getpid(),fpid);
引用一位网友的话来解释fpid的值为什么在父子进程中不同。“其实就相当于链表,进程形成了链表,父进程的fpid(p意味point)指向子进程的进程id,因为子进程没有子进程,所以其fpid为0.
fork出错可能有两种原因:
1)当前的进程数已经达到了系统规定的上限,这时errno的值被设置为EAGAIN。
2)系统内存不足,这时errno的值被设置为ENOMEM。
创建新进程成功后,系统中出现两个基本完全相同的进程,这两个进程执行没有固定的先后顺序,哪个进程先执行要看系统的进程调度策略。
每个进程都有一个独特(互不相同)的进程标识符(process ID),可以通过getpid()函数获得,还有一个记录父进程pid的变量,可以通过getppid()函数获得变量的值。
总结一下,这个程序执行的流程如下:
这个程序最终产生了3个子进程,执行过6次printf()函数。
我们再来看一份代码:
view plaincopy to clipboardprint?
01./*
02. * fork_test.c
03. * version 3
04. * Created on: 2010-5-29
else
printf("%d parent %4d %4d %4d\n",i,getppid(),getpid(),fpid);
}
return 0;
}
运行结果是:
i son/pa ppid pid fpid
0 parent 2043 3224 3225
0 child 3224 3225 0
1 parent 2043 3224 3226
p2043->p3224->p3225
第一次fork后,p3224(父进程)的变量为i=0,fpid=3225(fork函数在父进程中返向子进程id),代码内容为:
view plaincopy to clipboardprint?
01.for(i=0;i<2;i++){
02. pid_t fpid=fork();//执行完毕,i=0,fpid=3225
}
return 0;
所以打印出结果:
0 parent 2043 3224 3225
0 child 3224 3225 0
第二步:假设父进程p3224先执行,当进入下一个循环时,i=1,接着执行fork,系统中又新增一个进程p3226,对于此时的父进程,p2043->p3224(当前进程)->p3226(被创建的子进程)。
相关文档
最新文档