博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
关于fork函数
阅读量:6476 次
发布时间:2019-06-23

本文共 4349 字,大约阅读时间需要 14 分钟。

  一、怎么用fork

  fork是分叉,走叉路的意思。在代码时常常需要在一个进程中创建另一个新的进程,fork就是用来创建新进程的。创建完成之后原来的进程管它叫它父进程,而新的进程叫做子进程。其实父子是相对的,子有时候也会是父。

  关于fork()的一些说明可以参考一下这个:

  下面看一段代码

1 /*****************************************     2 filename:    testfork.c 3 Author:        zhouyoulie 4 date:        2013.05.27 5 *****************************************/ 6 #include 
7 #include
8 #include
9 #include
10 int main()11 {12 pid_t pid;13 int count = 0;14 printf("Before fork,process id is:%d\n",getpid());15 pid = fork();16 if( pid < 0 )17 {18 printf("Fork Failure!\n");19 }20 else if( pid == 0 )21 {22 printf("This is son process,and my own ID parent ID are:%d and %d\n",getpid(),getppid());23 count++;24 }25 else if( pid > 0 )26 {27 printf("the back pid is:%d\n",pid);28 printf("This is parent process,and my own ID parent ID are:%d and %d\n",getpid(),getppid());29 count++;30 }31 32 printf("count equals %d\n",count);33 exit(0);34 }
View Code1

  通过这段代码应该可以初略的了解fork的使用方法了。先说明两个函数:getpid()使用来获取当前进程的ID的,getppid()是用来获取当前进程的父进程ID。代码运行的结果是这样的

              

图1

  在调用fork之前本进程的ID是7301,调用fork之后返回7302,父进程和它自己的父进程ID分别为7301和4893,子进程和其父进程ID分别为7302和7301。结合上面的代码和运行结果不难看出fork被调用之后其实返回两次,返回的进程ID大于零说明该进程为父进程(其实返回的是他的子进程的ID,上图结果中的7302),返回值为零说明是子进程。那么两次count都为1说明什么呢?说明两个进程都独自拥有自己的count,实际上在生成子进程是就相当于克隆了一个自己,这种克隆包括数据、代码以及分配给进程的资源。

  二、fork的内部实现

  在用户态模式下调用fork时实际上调用的是C库提供的fork函数,在C库中封装了系统调用fork。在最新的内核代码linux3.9.3的

linux-3.9.3\include\uapi\asm-generic\unistd.h头文件中可查看相关系统调用号的定义,并且从unistd.h中还可以知道fork的系统调用例程为sys_fork,见图2

            

图2

  通过sys_fork可以追踪到linux-3.9.3\kernel\Fork.c,有如下实现

            

                                    图3

  在上述kernel实现里调用了do_fork,do_fork又是做什么的呢?继续查找代码可以觅得如下实现

1 long do_fork(unsigned long clone_flags, 2           unsigned long stack_start, 3           unsigned long stack_size, 4           int __user *parent_tidptr, 5           int __user *child_tidptr) 6 { 7     struct task_struct *p; 8     int trace = 0; 9     long nr;10 11     /*12      * Do some preliminary argument and permissions checking before we13      * actually start allocating stuff14      */15     if (clone_flags & (CLONE_NEWUSER | CLONE_NEWPID)) {16         if (clone_flags & (CLONE_THREAD|CLONE_PARENT))17             return -EINVAL;18     }19 20     /*21      * Determine whether and which event to report to ptracer.  When22      * called from kernel_thread or CLONE_UNTRACED is explicitly23      * requested, no event is reported; otherwise, report if the event24      * for the type of forking is enabled.25      */26     if (!(clone_flags & CLONE_UNTRACED)) {27         if (clone_flags & CLONE_VFORK)28             trace = PTRACE_EVENT_VFORK;29         else if ((clone_flags & CSIGNAL) != SIGCHLD)30             trace = PTRACE_EVENT_CLONE;31         else32             trace = PTRACE_EVENT_FORK;33 34         if (likely(!ptrace_event_enabled(current, trace)))35             trace = 0;36     }37 38     p = copy_process(clone_flags, stack_start, stack_size,39              child_tidptr, NULL, trace);40     /*41      * Do this prior waking up the new thread - the thread pointer42      * might get invalid after that point, if the thread exits quickly.43      */44     if (!IS_ERR(p)) {45         struct completion vfork;46 47         trace_sched_process_fork(current, p);48 49         nr = task_pid_vnr(p);50 51         if (clone_flags & CLONE_PARENT_SETTID)52             put_user(nr, parent_tidptr);53 54         if (clone_flags & CLONE_VFORK) {55             p->vfork_done = &vfork;56             init_completion(&vfork);57             get_task_struct(p);58         }59 60         wake_up_new_task(p);61 62         /* forking complete and child started to run, tell ptracer */63         if (unlikely(trace))64             ptrace_event(trace, nr);65 66         if (clone_flags & CLONE_VFORK) {67             if (!wait_for_vfork_done(p, &vfork))68                 ptrace_event(PTRACE_EVENT_VFORK_DONE, nr);69         }70     } else {71         nr = PTR_ERR(p);72     }73     return nr;74 }
View Code2

  在do_fork中又调用了copy_process函数。所以可以总结一下用户态与产生新进程的整体流程:

                  

                            图3

  

转载于:https://www.cnblogs.com/zhouyoulie/archive/2013/05/28/3104001.html

你可能感兴趣的文章
修改OBS为仅直播音频
查看>>
OCA读书笔记(3) - 使用DBCA创建Oracle数据库
查看>>
Python基础进阶之路(一)之运算符和输入输出
查看>>
阻塞非阻塞异步同步 io的关系
查看>>
ClickStat业务
查看>>
DMA32映射问题
查看>>
POJ 1269 Intersecting Lines(判断两直线位置关系)
查看>>
spring3.0.7中各个jar包的作用总结
查看>>
Windows 10 /win10 上使用GIT慢的问题,或者命令行反应慢的问题
查看>>
梯度下降(Gradient descent)
查看>>
Windows平台分布式架构实践 - 负载均衡
查看>>
iOS自定制tabbar与系统的tabbar冲突,造成第一次点击各个item图片更换选中,第二次选中部分item图片不改变...
查看>>
SVN服务器使用(二)
查看>>
反射获取内部类以及调用内部类方法
查看>>
App里面如何正确显示用户头像
查看>>
DATAGUARD维护:从库宕机后如何恢复到管理恢复模式
查看>>
U-BOOT之一:BootLoader 的概念与功能
查看>>
我的路上
查看>>
Velocity处理多余空白和多余空白行问题
查看>>
DB2与oracle有什么区别
查看>>