linux环境高级编程之fork、getpid、getppid函数

来源:互联网 发布:诺基亚5310xm软件 编辑:程序博客网 时间:2024/05/02 04:25

前段时间学习了fork函数创建进程,在fork创建后用execl函数来执行linux下的命令。



fork函数()

一个进程,包括代码、数据和分配给进程的资源。fork()函数通过系统调用创建一个与原来进程几乎完全相同的进程,也就是两个进程可以做完全相同的事,但如果初始参数或者传入的变量不同,两个进程也可以做不同的事。

    一个进程调用fork()函数后,系统先给新的进程分配资源,例如存储数据和代码的空间。然后把原来的进程的所有值都复制到新的新进程中,只有少数值与原来的进程的值不同。相当于克隆了一个自己。


用man fork 在linux下查看fork的用法

#include <unistd.h>       pid_t fork(void);

fork调用的一个奇妙之处就是它仅仅被调用一次,却能够返回两次,它可能有三种不同的返回值:
    1)在父进程中,fork返回新创建子进程的进程ID;
    2)在子进程中,fork返回0;
    3)如果出现错误,fork返回一个负值;
我们可以通过fork返回的值来判断当前进程是子进程还是父进程。

fpid的值为什么在父子进程中不同。“其实就相当于链表,进程形成了链表,父进程的fpid(p 意味point)指向子进程的进程id, 因为子进程没有子进程,所以其fpid为0.





getpid用来获取当前进程ID

getppid用来获取当前进程的父进程的ID

用法:  
#include <sys/types.h>
#include <unistd.h>

pid_t getpid(void);
pid_t getppid(void);



我写了一段代码用来加深理解

[fanmaolin@Centeros duojincheng]$ vim testfork.c   1 /*********************************************************************************  2  *      Copyright:  (C) 2017 fanmaolin<fanmaolinn@gmail.com>  3  *                  All rights reserved.  4  *  5  *       Filename:  testfork.c  6  *    Description:  This file   7  *                   8  *        Version:  1.0.0(05/09/2017)  9  *         Author:  fanmaolin <fanmaolinn@gmail.com> 10  *      ChangeLog:  1, Release initial version on "05/09/2017 07:28:18 PM" 11  *                  testfork.c                                                                                                                          12  ********************************************************************************/ 13  14 #include <sys/types.h> 15 #include <unistd.h> 16 #include <stdio.h> 17 int main () 18 { 19     pid_t fpid=fork(); //fpid表示fork函数返回的值   20      int count=0; 21  22     if (fpid < 0) 23         printf("error in fork!"); 24     else if (fpid == 0) 25     { 26         printf("我是子进程\n"); 27         printf("i am the child process, my process id is %d\n",getpid()); 28         printf("My Parents's process id is %d\n",getppid()); 29         count++; 30     } 31     else 32     { 33         printf("我是父进程\n"); 34         printf("i am the parent process, my process id is %d\n",getpid()); 35         count++; 36        sleep(1);//因为不确定父子进程谁会先执行,加个延时保证父进程先执行 37     } 38     printf("统计结果是: %d\n",count); 39     return 0; 40 }


执行结果




可以看到父进程ID为65869
子进程ID为65870
从子进程用getppid()获取父进程ID为65869
返回两次统计结果:1

父子进程间不确定谁会先执行。


问题总结:


关于为什么这里会返回两次1呢?

当父进程在执行的过程中,执行到sleep(1)时CPU分配给父进程的时间片到了,这时会执行子进程,执行完子进程后再来执行父进程,所以两个1是并列打印的,下面我们来看一下去掉sleep(1)的执行结果。

36 #ifdef SLEEP 37        sleep(1); 38 #endif

在这里有个技巧,因为有时我会用到sleep(1)有时又不会用到,加一个宏定义,如果我想用sleep时,
[fanmaolin@Centeros duojincheng]$ gcc testfork.c -o DSLEEP
[fanmaolin@Centeros duojincheng]$ ./a.out 
我是父进程
i am the parent process, my process id is 66512
我是子进程
i am the child process, my process id is 66513
My Parents's process id is 66512
统计结果是: 1
统计结果是: 1

如果我不想用sleep时

[fanmaolin@Centeros duojincheng]$ gcc testfork.c
[fanmaolin@Centeros duojincheng]$ ./a.out 
我是父进程
i am the parent process, my process id is 66527
统计结果是: 1
[fanmaolin@Centeros duojincheng]$ 我是子进程
i am the child process, my process id is 66528
My Parents's process id is 1
统计结果是: 1




看深红色字体,没有用sleep时的执行结果,会发现My Parents's process id is 1
子进程的父进程ID变成了“1”,这是为什么呢?
我们来看一下,哪一个进程的ID是1
[fanmaolin@Centeros duojincheng]$ ps auxUSER        PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMANDroot          1  0.0  0.1  19364  1264 ?        Ss   May08   0:03 /sbin/init

init进程的ID是1,原来我们不用sleep时,CPU如果先执行了父进程,父进程很快执行完了,子进程执行的时候没有了父进程,变成了孤儿进程,这个时候就被init进程收养了,所以子进程的父进程就变成了init进程。

在使用子进程的时候还要注意避免出现“僵尸进程”,所以要在父进程里给子进程“收尸”wait.

在分析类似问题时,一定要考虑到CPU时切片运行的,它留给每个程序的时间是有限的,差不多是ms级。
参考:
http://blog.csdn.net/jason314/article/details/5640969fork
http://www.cnblogs.com/wannable/p/6021617.html 孤儿进程、僵尸进程、守护进程