fork()的目的是什么?

在Linux的许多程序和手册页中,我看到了使用fork()代码。 为什么我们需要使用fork()以及它的用途是什么?

fork()是你如何在Unix中创build新的进程。 当你调用fork ,你正在创build一个拥有自己地址空间的进程的副本。 这允许多个任务彼此独立地运行,就好像它们各自具有机器的全部内存。

这里有一些fork例子用法:

  1. 你的shell使用fork来运行你从命令行调用的程序。
  2. 像apache这样的Web服务器使用fork来创build多个服务器进程,每个进程都在自己的地址空间中处理请求。 如果一个人死亡或泄漏内存,其他人不受影响,所以它起着容错机制的作用。
  3. Google Chrome使用fork来处理单独进程中的每个页面。 这将阻止一个页面上的客户端代码将整个浏览器closures。
  4. fork用于在一些并行程序(如使用MPI编写的程序)中产生进程。 请注意,这与使用不具有自己的地址空间并存在于进程的线程不同。
  5. 脚本语言间接使用fork来启动subprocess。 例如,每次在Python中使用类似subprocess.Popen的命令时,您都会forksubprocess并读取其输出。 这使程序能够一起工作。

fork在shell中的典型用法可能如下所示:

 int child_process_id = fork(); if (child_process_id) { // Fork returns a valid pid in the parent process. Parent executes this. // wait for the child process to complete waitpid(child_process_id, ...); // omitted extra args for brevity // child process finished! } else { // Fork returns 0 in the child process. Child executes this. // new argv array for the child process const char *argv[] = {"arg1", "arg2", "arg3", NULL}; // now start executing some other program exec("/path/to/a/program", argv); } 

shell使用exec产生一个subprocess并等待它完成,然后继续自己的执行。 请注意,您不必使用这种方式分叉。 你可以总是产生大量的subprocess,像一个并行程序可能做的那样,每个进程可以同时运行一个程序。 基本上,任何时候你在Unix系统中创build新的进程,你都使用fork() 。 对于Windows等价物,请看CreateProcess

如果你想要更多的例子和更长的解释, 维基百科有一个体面的总结。 这里有一些关于现代操作系统中的进程,线程和并发性的幻灯片 。

fork()是Unix如何创build新进程的。 在你调用fork()的地方,你的进程被克隆,两个不同的进程继续从那里执行。 其中一个孩子,将有fork()返回0.另一个,父,将有fork()返回父(PID)的进程ID。

例如,如果在shell中键入以下内容,shell程序将调用fork(),然后执行您在子项中传递的命令(在本例中为telnetd),而父项也将再次显示提示作为指示后台进程的PID的消息。

 $ telnetd & 

至于你创build新进程的原因,那就是你的操作系统可以同时做很多事情。 这就是为什么你可以运行一个程序,当它运行时,切换到另一个窗口,并做一些其他的事情。

fork()用于创buildsubprocess。 当fork()函数被调用时,会产生一个新的进程,并且fork()函数调用将为subprocess和父进程返回一个不同的值。

如果返回值是0,你知道你是subprocess,如果返回值是一个数字(恰好是subprocessID),你知道你是父进程。 (如果是负数,分叉失败并且没有创buildsubprocess)

http://www.yolinux.com/TUTORIALS/ForkExecProcesses.html

fork()将创build一个与父级相同的新subprocess。 因此,在这之后,在代码中运行的所有代码都将由两个进程运行 – 如果您有例如服务器,并且要处理多个请求,则非常有用。

fork()基本上是用来为你调用这个函数的过程创build一个subprocess。 每当你调用一个fork()的时候,它就会返回一个零子ID。

 pid=fork() if pid==0 //this is the child process else if pid!=0 //this is the parent process 

通过这个,你可以为父母和孩子提供不同的行为,并利用multithreadingfunction。

叉子创造新的过程。 没有fork你将有一个只能运行init的unix系统。

系统调用fork()用于创build进程。 它不需要参数并返回一个进程ID。 fork()的目的是创build一个新的进程,它成为调用者的subprocess。 在创build新的subprocess之后,两个进程都将执行fork()系统调用之后的下一条指令。 因此,我们必须区分父母和孩子。 这可以通过testingfork()的返回值来完成:

如果fork()返回负值,则创buildsubprocess失败。 fork()向新创build的subprocess返回一个零。 fork()返回一个正值,即父进程的subprocess的进程ID。 返回的进程ID是在sys / types.h中定义的typespid_t。 通常,进程ID是一个整数。 而且,一个进程可以使用函数getpid()来检索分配给这个进程的进程ID。 因此,在系统调用fork()之后,一个简单的testing就可以知道哪个进程是subprocess。 请注意,Unix将精确地复制父地址空间并将其提供给孩子。 因此,父进程和subprocess具有单独的地址空间。

让我们以一个例子来理解以上几点。 这个例子没有区分父进程和subprocess。

 #include <stdio.h> #include <string.h> #include <sys/types.h> #define MAX_COUNT 200 #define BUF_SIZE 100 void main(void) { pid_t pid; int i; char buf[BUF_SIZE]; fork(); pid = getpid(); for (i = 1; i <= MAX_COUNT; i++) { sprintf(buf, "This line is from pid %d, value = %d\n", pid, i); write(1, buf, strlen(buf)); } } 

假设上面的程序执行到fork()的调用点。

如果对fork()的调用成功执行,Unix将为两个地址空间创build两个相同的地址空间,一个用于父节点,另一个用于子节点。 这两个进程将在fork()调用之后的下一个语句处开始执行。 在这种情况下,两个进程将在分配中开始执行

 pid = .....; 

这两个进程在系统调用fork()之后立即开始执行。 由于这两个进程具有相同但是独立的地址空间,因此在fork()调用之前初始化的variables在两个地址空间中都具有相同的值。 由于每个进程都有自己的地址空间,所以任何修改都将独立于其他进程。 换句话说,如果父母改变其variables的值,修改将只影响父进程的地址空间中的variables。 由fork()调用创build的其他地址空间即使具有相同的variables名称也不会受到影响。

什么是使用写而不是printf的原因? 这是因为printf()是“缓冲的”,这意味着printf()会将进程的输出组合在一起。 当缓冲父进程的输出时,孩子也可以使用printf打印出一些信息,这些信息也将被缓冲。 因此,由于输出不会立即发送到屏幕,您可能无法获得预期结果的正确顺序。 更糟糕的是,这两个进程的输出可能会以奇怪的方式混合在一起。 为了克服这个问题,你可以考虑使用“无缓冲”的写法。

如果你运行这个程序,你可能会在屏幕上看到以下内容:

 ................ This line is from pid 3456, value 13 This line is from pid 3456, value 14 ................ This line is from pid 3456, value 20 This line is from pid 4617, value 100 This line is from pid 4617, value 101 ................ This line is from pid 3456, value 21 This line is from pid 3456, value 22 ................ 

进程ID 3456可以是分配给父母或孩子的人。 由于这些过程是同时进行的,它们的输出线以相当不可预知的方式混杂在一起。 而且,这些行的顺序是由CPU调度程序决定的。 因此,如果您再次运行此程序,则可能会得到完全不同的结果。

多处理是计算的核心。 例如,您的IE或Firefox可以创build一个stream程,在您浏览互联网的同时为您下载文件。 或者,当您在文字处理器中打印文档时,您仍然可以查看不同的页面,并仍然对其进行编辑。

如果您正在编写应用程序,那么您可能不需要在日常编程中使用fork。

即使你希望你的程序启动另一个程序来完成一些任务,还有其他一些在后台使用fork的简单界面,比如C和perl中的“system”。

例如,如果你想要你的应用程序启动另一个程序,比如bc来为你做一些计算,你可以使用'system'来运行它。 系统做一个“fork”来创build一个新的进程,然后是一个“exec”来把这个进程变成bc。 一旦bc完成,系统将控制返回到您的程序。

你也可以asynchronous运行其他程序,但我不记得如何。

如果你正在编写服务器,shell,病毒或者操作系统,你更可能要使用fork。

叉()用来创build每个人写的新进程。

这里是我的代码,以二叉树的forms创build进程…….它会要求扫描二进制树中要创build进程的级别数

 #include<unistd.h> #include<fcntl.h> #include<stdlib.h> int main() { int t1,t2,p,i,n,ab; p=getpid(); printf("enter the number of levels\n");fflush(stdout); scanf("%d",&n); printf("root %d\n",p);fflush(stdout); for(i=1;i<n;i++) { t1=fork(); if(t1!=0) t2=fork(); if(t1!=0 && t2!=0) break; printf("child pid %d parent pid %d\n",getpid(),getppid());fflush(stdout); } waitpid(t1,&ab,0); waitpid(t2,&ab,0); return 0; } 

OUTPUT

  enter the number of levels 3 root 20665 child pid 20670 parent pid 20665 child pid 20669 parent pid 20665 child pid 20672 parent pid 20670 child pid 20671 parent pid 20670 child pid 20674 parent pid 20669 child pid 20673 parent pid 20669 

首先需要了解什么是fork()系统调用。 让我解释

  1. fork()系统调用创build父进程的确切副本,它使父堆栈,堆,初始化数据,未初始化数据的副本与父进程以只读模式共享代码。

  2. 分叉系统调用在写时复制的基础上复制内存,当需要复制的时候是指虚拟内存页中的subprocess。

现在fork()的用途:

  1. Fork()可以在有分工的地方使用,就像服务器必须处理多个客户端一样,所以父母必须定期接受连接,所以服务器为每个客户端分叉执行读写操作。

fork()被用来产生一个subprocess。 它通常用于与线程类似的情况,但有不同之处。 与线程不同的是, fork()创build了完全独立的进程,这意味着subprocess和父进程是直接相互拷贝的,在调用fork()的时候,它们是完全独立的,既不能访问其他的内存空间不用去正常的麻烦你去访问另一个程序的内存)。

fork()仍然被一些服务器应用程序使用,其中大部分是在一个* NIX机器上以root用户身份运行的,在处理用户请求之前会丢失权限。 还有其他一些用例,但现在大多数人已经转向multithreading了。