Chinaunix首页 | 论坛 | 博客
  • 博客访问: 830003
  • 博文数量: 213
  • 博客积分: 5048
  • 博客等级: 大校
  • 技术积分: 1883
  • 用 户 组: 普通用户
  • 注册时间: 2008-04-14 10:14
文章分类

全部博文(213)

文章存档

2011年(4)

2010年(55)

2009年(47)

2008年(107)

我的朋友

分类: LINUX

2008-10-28 13:18:38

本文主要参考《unix环境高级编程》
 
fork函数:创建一个新的进程
 

#include <unistd.h>
pid_t fork(void);
返回值:子进程中返回0,父进程中返回子进程ID,出错返回-1.

fork将子进程ID返回给父进程的理由是:因为一个进程的子进程可以多于一个,所以没有一个函数使一个进程可以获得其所有子进程的进程ID。

fork使子进程得到返回值0的理由是:一个进程只会有一个父进程,所以子进程总是可以调用getppid以获得其父进程的进程ID (进程ID 0总是由交换进程使用,所以一个子进程的进程ID不可能为0 )。

父、子进程并不共享这些存储空间部分。如果正文段是只读的,则父、子进程共享正文段。

程序清单1 fork的函数实例

#include "apue.h"

int glob = 6;
char buf[]="a write to stdout\n";

int main(void)
{
    int var;
    pid_t pid;

    var = 88;
    if (write(STDOUT_FILENO, buf, sizeof(buf)-1) != (sizeof(buf)-1))/*对比作用,write不带缓冲*/
        err_sys("write error");
    printf("before fork\n");/*标准IO库函数,注意缓冲状态*/

    if ((pid =fork()) < 0){
        err_sys("fork error");
    } else if (pid == 0) { /*子进程*/
            glob ++;
            var ++;
    } else { /*父进程*/
        sleep(2);
    }

    printf("pid = %d, golb = %d, var = %d\n",getpid(),glob,var);    
    exit(0);
}

这段代码注意点:

1.fork之后是父进程先执行还是子进程先执行是不确定的,程序在父进程中调用sleep,作用就是让子进程先执行,但这不是一定的。

2.sizeof(buf)为什么要减一,因为sizeof计算的包括终止null字节的缓冲区长度,如果用strlen计算就不包括这个null字节。两者还有个区别,strlen需进行一次函数调用,而sizeof编译时计算缓冲区长度。

3.缓冲方式的问题,先看下面的执行结果:

$ a . o u t
a write to stdout
before fork
pid = 430, glob = 7, var = 89 子 进 程 的变量值改变了
pid = 429, glob = 6, var = 88 父 进 程 的变量值没有改变
$ a.out > temp.out
$ cat temp.out
a write to stdout
before fork
pid = 432, glob = 7, var = 89
before fork
pid = 431, glob = 6, var = 88

标准输出连到终端设备时是行缓冲,所以printf“before fork”后由换行符冲洗

标准输出重定向一个文件时是全缓冲,所以printf“before fork”一直留在缓冲区中,子进程复制时把这部分缓冲区内容也复制过去了,所以父子俩进程都会输出before fork。

这里为了比较还特地用write函数,write不是标准IO函数,所以是没有缓冲的,所以两种情况下,write都只是输出一次。

 

vfork:与fork差不多,就是在复制方面和fork很不一样,vfork在调用exec或者exit之前,他是在父空间中运行的。可以通过下面这个代码理解。

程序清单2 vfork的函数实例

#include "apue.h"

int glob = 6;

int
main(void)
{
    int var;
    pid_t pid;

    var = 88;
    printf("before vfork\n");

    if ((pid = vfork()) < 0) {
        err_sys("vfork error");
    } else if (pid == 0) {                /*子进程*/
        glob ++;
        var ++;
        _exit(0);
    } else {
        printf("father have came here");/*测试父进程能不能到这*/
    }

    /*
     *    父进程执行地方
     */

    printf("pid = %d, glob = %d, var = %d\n", getpid(), glob, var);
    exit(0);
}

从这段代码得到的信息:

1、由于想测试vfork是直接在父进程中运行的,所以我比书上多加一个else,测试证明这段代码是不会运行到这里的。

2、由于vfork实在父进程中运行,所以子进程一定是在父进程之前运行。

3、而且也由于vfork是在父进程中运行,所以子进程改变数据,会影响父进程中的输出,输出如下:

$ a . o u t
before vfork
pid = 607, glob = 7, var = 89

3、这里子进程中用_exit(0),是因为exit(0)会冲洗标准io流,而且有些系统会关闭标准io流,所以为了父进程中最后的printf能够正常输出,所以用_exit(0)。

 

阅读(850) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~