关于fork函数

  一、怎么用fork

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

  关于fork()的一些说明可以参考一下这个:http://man.he.net/?topic=fork&section=all

  下面看一段代码

 1 /*****************************************    
 2 filename:    testfork.c
 3 Author:        zhouyoulie
 4 date:        2013.05.27
 5 *****************************************/
 6 #include <stdlib.h>
 7 #include <stdio.h>
 8 #include <sys/types.h>
 9 #include <unistd.h>
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 we
13      * actually start allocating stuff
14      */
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.  When
22      * called from kernel_thread or CLONE_UNTRACED is explicitly
23      * requested, no event is reported; otherwise, report if the event
24      * 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         else
32             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 pointer
42      * 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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值