• fork函数笔记


    2014/7/11 20:54编辑: 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("出错啦!
    ");  
    11         else if (childpid == 0) /* 返回值为0 -- 该进程为子进程 */
    12                 printf("我是子进程!我的pid为%x
    ", getpid());   
    13         else if (childpid > 1) /*  
    14                                 * 返回值为正数 -- 该进程为父进程
    15                                 * 如果pid为1, 则表明父进程为init进程
    16                                 */
    17                 printf("我是父进程!我儿子的pid为%x
    ", 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!我只会显示一次!
    ", getpid());
     9         pid_t childpid = fork();
    10         if (childpid == -1)
    11                 printf("出错啦!
    ");
    12         else if (childpid == 0)  
    13                 printf("%x: Hello, world!我们父子会各自输出一次
    ", getpid());
    14         else if (childpid > 1)
    15                 printf("%x: Hello, world!我们父子会各自输出一次
    ", getpid());
    16         else /* 异常 */
    17                 assert(0);
    18         printf("%x: Hello, world!这次我们父子都会输出这条信息
    ", getpid());
    19         wait();
    20         return 0;
    21 } 
    /tmp louis$ gcc fork2.c -o f2
    /tmp louis$ ./f2
    1c3e: Hello, world!我只会显示一次!
    1c3e: Hello, world!我们父子会各自输出一次
    1c3e: Hello, world!这次我们父子都会输出这条信息
    1c3f: Hello, world!我们父子会各自输出一次
    1c3f: Hello, world!这次我们父子都会输出这条信息
    /tmp louis$ ./f2
    1c40: 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("出错啦!
    ");
    12         else if (childpid == 0) {
    13                 i = 1;
    14                 printf("子进程%x: i = %d
    ", getpid(), i);
    15         } else if (childpid > 1) {
    16                 i += 1;
    17                 printf("父进程%x: i = %d
    ", getpid(), i);
    18         } else   
    19                 assert(0);
    20         printf("%x: i = %d
    ", getpid(), i);
    21         wait();
    22         return 0;
    23 } 
    /tmp louis$ gcc fork3.c -o f3
    /tmp louis$ ./f3
    父进程1c88: i = 1
    1c88: i = 1
    子进程1c89: i = 1
    1c89: i = 1
    /tmp louis$ ./f3
    父进程1c8a: i = 1
    1c8a: i = 1
    子进程1c8b: i = 1
    1c8b: i = 1
    /tmp louis$  

    子进程和父进程是完全不同的两个进程,父子进程要分别占用不同的资源。
     
    最后出一道练习题:下面的代码执行后会有什么效果呢?

    #include <unistd.h>
    int main(void)  
    {
            while (1)
                    fork();
            return 0;
    } 

    大家想不出来可千万别自己去尝试呀,呵呵.

  • 相关阅读:
    JVM对象
    JVM如何加载Java类
    JVM内存模型
    JVM的直接内存
    docker run命令
    JVM调优-CPU占用过高
    JVM调优工具
    Java爬虫爬取京东商品信息
    Linux下设置Tomcat虚拟路径
    Java设计模式之-------->"代理模式"
  • 原文地址:https://www.cnblogs.com/KM-Y/p/3790623.html
Copyright © 2020-2023  润新知