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 stdoutbefore forkpid=2472,glob=67,var=89before fork//注意该字符串一共输出了两次pid=2471,glob=66,var=88