新手如何理解fork函数_华清远见
- 格式:docx
- 大小:57.47 KB
- 文档页数:8
C++ fork线程函数C++中,线程是一种轻量级的进程,允许不同的任务同时运行。
而fork是另一种创建进程的方法,它可以在父进程的基础上创建一个新的子进程。
本文就将介绍如何使用C++的fork函数创建进程。
1. fork的定义fork函数在C++中的定义如下:pid_t fork(void);这个函数的作用是在当前进程中创建一个新进程。
新进程与当前进程创建完全相同,除了进程ID和父进程ID不同外。
在新进程中,fork返回0;在父进程中,fork返回新进程的ID;如果没有成功创建进程,fork返回-1。
2. fork的用法用法如下所示:pid_t pid = fork();if(pid == 0) {// 子进程} else if(pid > 0) {// 父进程} else {// fork失败}3. 使用示例下面是一个简单的示例,在父进程和子进程中分别输出一句话。
#include <iostream>#include <unistd.h>#include <sys/wait.h>using namespace std;int main() {pid_t pid = fork();if(pid == 0) {// 子进程cout << "This is child process." << endl;} else if(pid > 0) {// 父进程cout << "This is parent process." << endl;wait(NULL); // 等待子进程结束} else {// fork失败cout << "fork failed." << endl;return -1;}return 0;}输出结果:This is parent process.This is child process.4. 注意事项fork函数有一些注意事项需要注意。
一、fork入门知识一个进程,包括代码、数据和分配给进程的资源。
fork()函数通过系统调用创建一个与原来进程几乎完全相同的进程,也就是两个进程可以做完全相同的事,但如果初始参数或者传入的变量不同,两个进程也可以做不同的事。
一个进程调用fork()函数后,系统先给新的进程分配资源,例如存储数据和代码的空间。
然后把原来的进程的所有值都复制到新的新进程中,只有少数值与原来的进程的值不同。
相当于克隆了一个自己。
我们来看一个例子:view plaincopy to clipboardprint?/** fork_test.c* version 1* Created on: 2010-5-29* Author: wangth*/#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 ",getpid());printf("我是爹的儿子");//对某些人来说中文看着更直白。
count++;}else {printf("i am the parent process, my process id is %d ",getpid());printf("我是孩子他爹");count++;}printf("统计结果是: %d ",count);return 0;}/** fork_test.c* version 1* Created on: 2010-5-29* Author: wangth*/#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 ",getpid());printf("我是爹的儿子");//对某些人来说中文看着更直白。
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信息相同,用户态代码和数据也相同。
多进程中的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函数是一个非常重要的系统调用,它用于创建一个新的进程。
本文将详细解释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英文原意是"分岔,分支"的意思,而在操作系统中,乃是著名的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函数创建⼀个新进程。
#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函数是一个非常常见和重要的函数,常常用于创建子进程和控制进程的运行。
在本文中,我们将深入讨论这个函数和它的使用。
一、什么是fork函数?首先,让我们来了解一下什么是fork函数。
fork是Linux中的一个系统调用,它可以用来创建一个新的进程,从父进程复制出一个子进程。
一个进程可以通过调用fork 函数来创建一个完全独立的子进程,子进程将复制父进程的地址空间、寄存器和文件描述符等资源,但是独立于父进程的运行,它们可以独立于父进程运行、执行不同的任务。
二、fork函数的使用方法1. 函数原型在使用fork函数之前,我们应该先学习一下它的函数原型:pid_t fork(void);这个frok函数返回值是pid_t类型的,表示进程的ID号。
当fork函数成功创建一个新的进程时,如果是在父进程中调用,返回的是子进程的ID号,如果是在子进程中调用,返回的是零。
如果fork函数执行失败则返回-1。
2. 父进程和子进程的区别在fork函数被调用之后,进程将会被分成两个进程:父进程和子进程。
这两个进程是分开的、独立的,它们有独立的内存地址空间、独立的寄存器、独立的文件描述符等。
在父进程中,fork函数的返回值是子进程的ID号,所以我们可以通过这个返回值来判断是父进程还是子进程在运行。
比如:pid_t pid = fork(); if (pid == 0){ printf("This is child process\n"); } else if (pid > 0) { printf("This is parentprocess\n"); } else { printf("Forkfailed!\n"); }在子进程中,fork函数的返回值是零,所以此时会输出“This is child process”。
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函数,所以就写了一篇关于新手如何理解fork函数的文章。
首先我们来看看,什么是fork函数:计算机程序设计中的分叉函数。
返回值:若成功调用一次则返回两个值,子进程返回0,父进程返回子进程标记;否则,出错返回-1。
fork函数将运行着的程序分成2个(几乎)完全一样的进程,每个进程都启动一个从代码的同一位置开始执行的线程。
这两个进程中的线程继续执行,就像是两个用户同时启动了该应用程序的两个副本。
正题开始了,对于刚刚接触Unix/Linux操作系统,在Linux下编写多进程的人来说,fork是最难理解的概念之一:它执行一次却返回两个值。
首先我们来看下fork函数的原型:#i nclude#i ncludepid_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#includeint main(){pid_tpid;int count=0;pid = fork();printf( "This is first time, pid = %d\n", pid );printf( "This is second 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#includeint main(void){pid_tpid;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 process,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;}运行结果如下:现在来解释上面提出的问题。
看这个程序的时候,头脑中必须首先了解一个概念:在语句pid=fork()之前,只有一个进程在执行这段代码,但在这条语句之后,就变成两个进程在执行了,这两个进程的代码部分完全相同,将要执行的下一条语句都是if ( pid>0 )……。
两个进程中,原先就存在的那个被称作“父进程”,新出现的那个被称作“子进程”。
父子进程的区别除了进程标志符(process ID)不同外,变量pid的值也不相同,pid存放的是fork的返回值。
fork调用的一个奇妙之处就是它仅仅被调用一次,却能够返回两次,它可能有三种不同的返回值:1. 在父进程中,fork返回新创建子进程的进程ID;2.在子进程中,fork返回0;3.如果出现错误,fork返回一个负值;fork出错可能有两种原因:(1)当前的进程数已经达到了系统规定的上限,这时errno的值被设置为EAGAIN。
(2)系统内存不足,这时errno的值被设置为ENOMEM。
接下来我们来看看APUE2中对fork的说明:The new process created by fork is called the child process. This function is called once but returns twice. The only difference in the returns is that the return value in the child is 0, whereas the return value in the parent is the process ID of the new child. The reason the child's process ID is returned to the parent is that a process can have more than one child, and there is no function that allows a process to obtain the process IDs of its children. The reason fork returns 0 to the child is that a process can have only a single parent, and the child can always call getppid to obtain the process ID of its parent. (Process ID 0 is reserved for use by the kernel, so it's not possible for 0 to be the process ID of a child.)被fork创建的新进程叫做自进程。
fork函数被调用一次,却两次返回。
返回值唯一的区别是在子进程中返回0,而在父进程中返回子进程的pid。
在父进程中要返回子进程的pid的原因是父进程可能有不止一个子进程,而一个进程又没有任何函数可以得到他的子进程的pid。
Both the child and the parent continue executing with the instruction that follows the call to fork. The child is a copy of the parent. For example, the child gets a copy of the parent's data space, heap, and stack. Note that this is a copy for the child; the parent and the child do not share these portions of memory. The parent and the child share the text segment (Section 7.6).子进程和父进程都执行在fork函数调用之后的代码,子进程是父进程的一个拷贝。
例如,父进程的数据空间、堆栈空间都会给子进程一个拷贝,而不是共享这些内存。
Current implementations don't perform a complete copy of the parent's data, stack, and heap, since a fork is often followed by an exec. Instead, a technique called copy-on-write (COW) is used. These regions are shared by the parent and the child and have their protection changed by the kernel to read-only. If either process tries to modify these regions, the kernel then makesa copy of that piece of memory only, typically a "page" in a virtual memory system. Section 9.2 of Bach [1986] and Sections 5.6 and 5.7 of McKusick et al. [1996] provide more detail on this feature.我们来给出详细的注释#include#includeint main(void){pid_tpid;int count=0;/*此处,执行fork调用,创建了一个新的进程,这个进程共享父进程的数据和堆栈空间等,这之后的代码指令为子进程创建了一个拷贝。
fock 调用是一个复制进程,fock不象线程需提供一个函数做为入口, fock调用后,新进程的入口就在 fock的下一条语句。