您当前的位置:首页 > 好词好句 > 正文

fork函数(关于fork()函数,谁来解释一下)

本文目录

  • 关于fork()函数,谁来解释一下
  • 什么是fork,它是干什么的,有什么作用
  • linux下的fork函数
  • fork的分叉函数
  • fork函数
  • fork函数问题
  • 如何创建守护进程fork函数的运用
  • fork()函数真正被实现的文件是哪个

关于fork()函数,谁来解释一下

fork()的结果是生成一个新的进程。新的进程和原来的进程不共享数据。你把原进程中的a在打印前就另外赋值也不会影响新进程中的a。两个进程中a的(虚拟)地址一样是因为新进程是原进程的拷贝,除了和进程相关的一些数据不同,其它都一样。现代操作系统都使用虚拟地址。不同进程都可以使用同样大小的虚拟地址空间(32位操作系统为4G),有操作系统和处理器硬件完成虚拟地址到物理地址的转换。一个进程中的虚拟地址数值在另一个进程中毫无意义,即便两个进程中虚拟地址一样,其物理地址完全不同。

什么是fork,它是干什么的,有什么作用

在Linux下产生新的进程的系统调用就是fork函数,这个函数名是英文中“分叉”的意思。为什么取这个名字呢?因为一个进程在运行中,如果使用了fork,就产生了另一个进程,于是进程就“分叉”了,所以这个名字取得很形象。下面就看看如何具体使用fork,这段程序演示了使用fork的基本框架: void main(){ int I; if ( fork() == 0 ) { /* 子进程程序 */ for ( I = 1; I 《1000; I ++ ) printf(“This is child process\n“); } else { /* 父进程程序*/ for ( I = 1; I 《1000; I ++ ) printf(“This is process process\n“); } } 程序运行后,你就能看到屏幕上交替出现子进程与父进程各打印出的一千条信息了。如果程序还在运行中,你用ps命令就能看到系统中有两个它在运行了。 那么调用这个fork函数时发生了什么呢?一个程序一调用fork函数,系统就为一个新的进程准备了前述三个段,首先,系统让新的进程与旧的进程使用同一个代码段,因为它们的程序还是相同的,对于数据段和堆栈段,系统则复制一份给新的进程,这样,父进程的所有数据都可以留给子进程,但是,子进程一旦开始运行,虽然它继承了父进程的一切数据,但实际上数据却已经分开,相互之间不再有影响了,也就是说,它们之间不再共享任何数据了。而如果两个进程要共享什么数据的话,就要使用另一套函数(shmget,shmat,shmdt等)来操作。现在,已经是两个进程了,对于父进程,fork函数返回了子程序的进程号,而对于子程序,fork函数则返回零,这样,对于程序,只要判断fork函数的返回值,就知道自己是处于父进程还是子进程中。 读者也许会问,如果一个大程序在运行中,它的数据段和堆栈都很大,一次fork就要复制一次,那么fork的系统开销不是很大吗?其实UNIX自有其解决的办法,大家知道,一般CPU都是以“页”为单位分配空间的,象INTEL的CPU,其一页在通常情况下是4K字节大小,而无论是数据段还是堆栈段都是由许多“页”构成的,fork函数复制这两个段,只是“逻辑”上的,并非“物理”上的,也就是说,实际执行fork时,物理空间上两个进程的数据段和堆栈段都还是共享着的,当有一个进程写了某个数据时,这时两个进程之间的数据才有了区别,系统就将有区别的“页”从物理上也分开。系统在空间上的开销就可以达到最小。

linux下的fork函数

不止三个,子进程仍然在循环体内,所以子进程也会根据它的i值来做循环,然后fork子进程的子进程,但是你的程序也有问题,父进程打印后没有等待子进程运行结束就return了,这样有些子进程还来不仅运行就退出了。所以你的程序的输出结果是不可靠的,也是可能是随机的(其结果会根据运行时操作系统的具体调度的不同而不同)。所以我给你改了一下,这样就能让所有被fork的子进程(包括这些子进程再次fork出来的子进程)都有机会运行。int main(){ int i; int my_pid; int chld_pid; for( i= 0; i《 3; i++) { chld_pid= fork(); if(chld_pid== 0) { my_pid = getpid(); printf(“i = %d, child pid %d\n“, i, my_pid); } else { my_pid = getpid(); printf(“i = %d, parent pid %d, child pid %d\n“,i, my_pid, chld_pid); wait(0); /*waiting for the completion of child */ } } return 0;}运行后的结果为:i = 0, parent pid 5294, child pid 5295i = 0, child pid 5295i = 1, parent pid 5295, child pid 5296i = 1, child pid 5296i = 2, parent pid 5296, child pid 5297i = 2, child pid 5297i = 2, parent pid 5295, child pid 5298i = 2, child pid 5298i = 1, parent pid 5294, child pid 5299i = 1, child pid 5299i = 2, parent pid 5299, child pid 5300i = 2, child pid 5300i = 2, parent pid 5294, child pid 5301i = 2, child pid 5301这样你就可以看到,实际上有7个子进程被fork出来,其中有3个是被真正的父进程(5294)fork出来的,而其余的则是被5294的子进程(甚至子进程的子进程)所fork出来的。其中的逻辑关系从打印出来的进程号就可以一目了然了,我就不赘述了。

fork的分叉函数

pid_t fork( void);(pid_t 是一个宏定义,其实质是int 被定义在#include《sys/types.h》中)返回值: 若成功调用一次则返回两个值,子进程返回0,父进程返回子进程ID;否则,出错返回-1 一个现有进程可以调用fork函数创建一个新进程。由fork创建的新进程被称为子进程(child process)。fork函数被调用一次但返回两次。两次返回的唯一区别是子进程中返回0值而父进程中返回子进程ID。子进程是父进程的副本,它将获得父进程数据空间、堆、栈等资源的副本。注意,子进程持有的是上述存储空间的“副本”,这意味着父子进程间不共享这些存储空间。UNIX将复制父进程的地址空间内容给子进程,因此,子进程有了独立的地址空间。在不同的UNIX (Like)系统下,我们无法确定fork之后是子进程先运行还是父进程先运行,这依赖于系统的实现。所以在移植代码的时候我们不应该对此作出任何的假设。为什么fork会返回两次?由于在复制时复制了父进程的堆栈段,所以两个进程都停留在fork函数中,等待返回。因此fork函数会返回两次,一次是在父进程中返回,另一次是在子进程中返回,这两次的返回值是不一样的。过程如下图。 fork调用的一个奇妙之处就是它仅仅被调用一次,却能够返回两次,它可能有三种不同的返回值:  在父进程中,fork返回新创建子进程的进程ID; 在子进程中,fork返回0; 如果出现错误,fork返回一个负值。 在fork函数执行完毕后,如果创建新进程成功,则出现两个进程,一个是子进程,一个是父进程。在子进程中,fork函数返回0,在父进程中,fork返回新创建子进程的进程ID。我们可以通过fork返回的值来判断当前进程是子进程还是父进程。引用一位网友的话来解释fork函数返回的值为什么在父子进程中不同。“其实就相当于链表,进程形成了链表,父进程的fork函数返回的值指向子进程的进程id, 因为子进程没有子进程,所以其fork函数返回的值为0.调用fork之后,数据、堆、栈有两份,代码仍然为一份但是这个代码段成为两个进程的共享代码段都从fork函数中返回,箭头表示各自的执行处。当父子进程有一个想要修改数据或者堆栈时,两个进程真正分裂。示例代码: #include《sys/types.h》//对于此程序而言此头文件types.h用不到#include《unistd.h》#include《stdio.h》#include《stdlib.h》int main(int argc,char *argv)/*整数类型主函数*/{pid_t pid=fork();/*传递参数*/if(pid《0)/*如果(进程标记《0)*/{fprintf(stderr,错误!);}else if(pid==0)/*否则如果(进程标记==0)*/{printf(百度百科:这是子进程!);exit(0);}else/*否则*/{printf(百度百科:这是父进程!子进程的进程标记为=%d,pid);}//可能需要时候wait或waitpid函数等待子进程的结束并获取结束状态exit(0);}注意!样例代码仅供参考,样例代码存在着父进程在子进程结束前结束的可能性。必要的时候可以使用wait或 waitpid函数让父进程等待子进程的结束并获取子进程的返回状态。fork()在Linux系统中的返回值是没有NULL的.Error Codes出错返回错误信息如下:EAGAIN达到进程数上限.ENOMEM 没有足够空间给一个新进程分配.fork函数的特点概括起来就是“调用一次,返回两次”,在父进程中调用一次,在父进程和子进程中各返回一次。fork的另一个特性是所有由父进程打开的描述符都被复制到子进程中。父、子进程中相同编号的文件描述符在内核中指向同一个file结构体,也就是说,file结构体的引用计数要增加。

fork函数

...if (!fork()){ A;}else{ B;}C;...fork函数,在子进程中返回的值是0,在父进程中返回的是子进程的进程ID。所以,上面的代码是,父进程会执行B,C,...子进程会执行A,C,... 至于fork函数的实现,实际上它是操作系统实现的一个系统调用。只不过,我们调用的C库函数,是把这个系统调用封装了一下罢了.

fork函数问题

fork()函数用于创建子进程,新创建的子进程拥有和父进程一样的资源(比如相同的代码,相同的执行位置),如果函数失败会返回负值。while ((p1 = fork()) == -1); 目的是: 1.将fork的返回值赋给p1; 2. 如果函数失败则再次调用,知道成功为止. 这段代码会创建一个子进程,当创建子进程时,子进程和父进程都会从同一个起点执行相同的代码(从while 后面的语句开始), 然后执行到if语句, 因为fork函数对于子进程会返回0, 对于父进程会返回子进程的ID(标识符),所以当执行到if时, 父进程执行putchar(’a’),子进程执行putchar(’b’);

如何创建守护进程fork函数的运用

你好,编写守护进程只要遵循一个特定的流程,就很方便写出自己的守护进程。第一步、创建子进程,父进程退出;pid = fork()if (pid 》 0){exit(0); //父进程退出}第二步、在子进程中创建新会话;第三步、改变当前目录为根目录;第四步、重设文件权限掩码;第五步、关闭文件描述符;这样就基本创建了一个守护进程。下面看一个实例:作用是让该守护进程每隔10秒向日志文件/tmp/daemon.log中写入一句话。[cpp] view plaincopy/* * daemon.c * * Created on: 2012-7-13 * Author: liwei.cai */ #include 《stdlib.h》 #include 《stdio.h》 #include 《string.h》 #include 《fcntl.h》 #include 《sys/types.h》 #include 《unistd.h》 #include 《sys/wait.h》 int main() { pid_t pid; int i, fd; char *buf =“This is a Daemon\n“; pid = fork(); //第一步 创建子进程,父进程退出 if (pid 《 0) { printf(“Error fork\n“); exit(1); } else if (pid 》0) { exit(0);// 父进程退出 } setsid();//第二步 在子进程中创建新会话 chdir(“/“);//第三步 改变当前目录为根目录 umask(0);//第四步 重设文件权限掩码 for(i = 0; i 《 getdtablesize(); i++) //第五步 关闭文件描述符 { close(i); } //这时候已经创建完成守护进程,以下开始正式进入守护进程工作 while(1) { if((fd = open(“/tmp/daemon.log“, O_CREAT|O_WRONLY|O_APPEND,0600)) 《 0) { printf(“Open file error\n“); exit(1); } write(fd, buf, strlen(buf)+1); close(fd); sleep(10); } exit(0); }

fork()函数真正被实现的文件是哪个

fork 实际上是操作系统提供的系统调用 (syscall),它是由操作系统,比如你在linux系统上,就要看内核源码。至于程序中我们使用的 fork 接口本身,是由标准C库,libc 实现的,它其实很简单,直接调用了操作系统提供的系统调用。如果你是想看这个,去下载 glibc 源码找吧,不过没什么意义,对于系统调用来说,libc只是起个二传手的作用,自己什么都不做。在linux内核源码中 linux-2.6.32.10/arch/x86/kernel/syscall_table_32.S 中是所有系统调用接口定义的地方。 搜索之后你会发现 sys_fork 最终调用了 do_fork再在 linux-2.6.32.10/kernel/fork.c 可以看到 do_fork的实现。所以具体的代码就在 kernel/fork.c 里了。注意,你必须下载kernel源码才能找到上面提到的信息。


声明:本文版权归原作者所有,转载文章仅为传播更多信息之目的,如作者信息标记有误,请第一时间联系我们修改或删除,谢谢。

上一篇: solar panel(新房装修,想装太阳能,太阳能能使用多长时间)

下一篇: csdn登陆(csdn怎么登陆不了了,为什么)



推荐阅读