- 论坛徽章:
- 0
|
本文主要参考《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)。
本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u2/66435/showart_1347313.html |
|