首页 > 代码库 > 系统调用fork笔记
系统调用fork笔记
fork函数的原型是这样的:
1 pid_t fork(void);
它实际上是一个系统调用,被包装在unistd.h中
由fork创建的新进程称为子进程,创建子进程的进程叫做父进程.子进程拥有与父进程一模一样的数据,从fork()语句开始分化.
它的返回值类型pid_t是一个内容为int的宏,在sys/types.h中声明.子进程返回0,父进程中返回子进程的pid(可以在子进程中调用getpid()得到,它同样被包装在unistd.h中).出错返回-1.出错原因可能是当前进程数超过限定或内存不足以新建一个进程.
除了init进程外,每一个进程都有一个父进程.init进程没有父进程,可以说,所有进程都是init进程fork出来的.
下面这个程序演示了fork函数.
1 #include <assert.h> 2 #include <unistd.h> 3 #include <sys/types.h> 4 #include <stdio.h> 5 6 int main(void) 7 { 8 pid_t childpid = fork(); /* 从这一行开始,子进程开始 */ 9 if (childpid == -1) /* 返回值为-1 -- 出错 */ 10 printf("出错啦!\n"); 11 else if (childpid == 0) /* 返回值为0 -- 该进程为子进程 */12 printf("我是子进程!我的pid为%x\n", getpid()); 13 else if (childpid > 1) /* 14 * 返回值为正数 -- 该进程为父进程15 * 如果pid为1, 则表明父进程为init进程16 */17 printf("我是父进程!我儿子的pid为%x\n", childpid);18 else /* 异常 */19 assert(0);20 return 0;21 }
/tmp louis$ gcc fork1.c -o f/tmp louis$ ./f我是父进程!我儿子的pid为1bf0我是子进程!我的pid为1bf0/tmp louis$ ./f我是父进程!我儿子的pid为1bf9我是子进程!我的pid为1bf9/tmp louis$ ./f我是父进程!我儿子的pid为1bfb我是子进程!我的pid为1bfb/tmp louis$ ./f我是父进程!我儿子的pid为1bfd我是子进程!我的pid为1bfd/tmp louis$
再看一个例子:
1 #include <assert.h> 2 #include <unistd.h> 3 #include <sys/types.h> 4 #include <stdio.h> 5 6 int main(void) 7 { 8 printf("%x: Hello, world!我只会显示一次!\n", getpid()); 9 pid_t childpid = fork();10 if (childpid == -1)11 printf("出错啦!\n");12 else if (childpid == 0) 13 printf("%x: Hello, world!我们父子会各自输出一次\n", getpid());14 else if (childpid > 1)15 printf("%x: Hello, world!我们父子会各自输出一次\n", getpid());16 else /* 异常 */17 assert(0);18 printf("%x: Hello, world!这次我们父子都会输出这条信息\n", getpid());19 wait();20 return 0;21 }
/tmp louis$ gcc fork2.c -o f2/tmp louis$ ./f21c3e: Hello, world!我只会显示一次!1c3e: Hello, world!我们父子会各自输出一次1c3e: Hello, world!这次我们父子都会输出这条信息1c3f: Hello, world!我们父子会各自输出一次1c3f: Hello, world!这次我们父子都会输出这条信息/tmp louis$ ./f21c40: Hello, world!我只会显示一次!1c40: Hello, world!我们父子会各自输出一次1c40: Hello, world!这次我们父子都会输出这条信息1c41: Hello, world!我们父子会各自输出一次1c41: Hello, world!这次我们父子都会输出这条信息/tmp louis$
倒数第3行的wait()调用的意思是:如果该进程拥有子进程且子进程还在运行,那么等待子进程结束后再继续执行之后的语句.
如果不加上这个调用,父进程就有可能先于子进程结束.这意味着,该父进程fork出的子进程没有了父进程,成了"孤儿"进程.这时,init进程会立刻"领养"该"孤儿"进程,成为"孤儿"进程的父进程.然后,被领养的"孤儿"进程结束运行后,内存中还保留这相关信息.这时,它就会变成"僵尸"进程,占用着宝贵的资源.
再看最后一个例子吧.这个例子说明了父子进程之间的数据资源并非共享.
1 #include <assert.h> 2 #include <unistd.h> 3 #include <sys/types.h> 4 #include <stdio.h> 5 6 int main(void) 7 { 8 int i = 0; 9 pid_t childpid = fork();10 if (childpid == -1)11 printf("出错啦!\n");12 else if (childpid == 0) {13 i = 1;14 printf("子进程%x: i = %d\n", getpid(), i);15 } else if (childpid > 1) {16 i += 1;17 printf("父进程%x: i = %d\n", getpid(), i);18 } else 19 assert(0);20 printf("%x: i = %d\n", getpid(), i);21 wait();22 return 0;23 }
/tmp louis$ gcc fork3.c -o f3/tmp louis$ ./f3父进程1c88: i = 11c88: i = 1子进程1c89: i = 11c89: i = 1/tmp louis$ ./f3父进程1c8a: i = 11c8a: i = 1子进程1c8b: i = 11c8b: i = 1/tmp louis$
子进程和父进程是完全不同的两个进程,父子进程要分别占用不同的资源。
最后出一道练习题:下面的代码执行后会有什么效果呢?
#include <unistd.h>int main(void) { while (1) fork(); return 0;}
大家想不出来可千万别自己去尝试呀,呵呵.
<style></style>
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。