前段时间学习了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
我是父进程
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
[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 aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 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.youkuaiyun.com/jason314/article/details/5640969
fork
http://www.cnblogs.com/wannable/p/6021617.html
孤儿进程、僵尸进程、守护进程