1、典型的存储器安排
2、fork函数:fork后,子进程获得父进程的数据空间、堆、栈、其缓冲区的副本(但由于在fork之后经常跟随着exec,所以现实的很多实现并不执行父进程的数据段、栈和堆的完全复制)
代码说明:
#include "apue.h"
//如果标准输出连到 终端设备时,则它是行缓冲
//如果标准输出重定向到一个文件时,则它是全缓冲,因此before fork会输出两次到
int ff=66;
char buf[]="a write to stdout\n";
int main(int argc,char ** argv){
int var;
pid_t pid;
var =88;
if(write(STDOUT_FILENO,buf,sizeof(buf)-1)!=sizeof(buf)-1)//输出到标准输出
err_sys("write error");
printf("before fork\n");//该字符串存放在其缓冲区中(若是行缓冲,遇\n换行符就冲洗该缓冲区)
if((pid=fork())<0){
err_sys("fork error!!!");
}
else if(pid==0){
ff++;
var++;
}
else {
sleep(2);
}
printf("pid=%d,glob=%d,var=%d\n",getpid(),ff,var);
exit(0);
}
3、Vfork函数:vfork用于创建一个新进程,而该新进程的目的是exec一个新程序,因此它并不将父进程的地址空间完全复制到子进程中,相反,而是在子进程调用exec或exit之前,它在父进程的空间中运行(即与父进程共用同一数据段)
代码说明:
#include"apue.h"
int gg =6;//全局变量
int main(int argc,char **argv){
int var;//局部变量
var =88;
pid_t pid;
printf("before vfork\n");
if((pid=vfork())<0){//vfork函数并不将父进程的地址空间完全复制到子进程中,而是子进程在调用exec或exit之前,和父进程共用空间
err_sys("vfork error");
} else if(pid==0){
gg++;
var++;
//_exit(0);//不冲洗其缓冲区,直接进入内核
exit(0);//冲洗父其缓冲区后,然后进入内核
}
printf("pid=%d, gg=%d ,var=%d\n",getpid(),gg,var);
exit(0);
}
输出:
a write to stdout
before fork
pid=2472,glob=67,var=89
before fork//注意该字符串一共输出了两次
pid=2471,glob=66,var=88