}
#include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <unistd.h> void test() { pid_t pid; pid=vfork(); if(pid<0) //失败 { printf("vfork error\n"); exit(0); } else if(pid==0) { printf("1:child pid=%d,ppid=%d\n",getpid(),getppid()); return; //return执行完后,把控制权交给调用函数,而exit()执行完后把控制权交给系统 ,改成_exit(0),则会有另一种结果 } else { printf("2:parent pid=%d,ppid=%d\n",getpid(),getppid()); } } void fun() { int i=0; int buf[100]; for(;i<100;i++) { buf[i]=0; } printf("3:child pid=%d,ppid=%d\n",getpid(),getppid()); } int main() { test(); fun(); return 0; }Makefile
运行结果
程序在后续执行时出现了错误,并且可知道是在父进程中出现的错误
vfork函数调用时,子进程比父进程先运行,在调用test()函数执行时,子进程执行完之后,将清理test函数的栈空间,然后子进程再调用fun()函数,将覆盖掉test的栈空间,继续执行fun函数。但是,当子进程退出后,执行父进程,但是,在test函数返回的时候该栈空间已经被子进程破坏了,不存在了,所以就出现了栈错误
区别:
1.vfork保证子进程先运行,在它调用exec或者exit之后,父进程才可能被调度运行,之后,父子进程的执行顺序才不再有限制。如果在调用exec或者exit之前,子进程依赖于父进程的进一步动作,则会导致死锁
2.fork要拷贝父进程的进程环境(数据段),而vfork不需要完全拷贝父进程的进程环境(数据段),在调用exec或者exit之前,父子进程共享进程环境(数据段),相当于线程概念,此时父进程阻塞等待(因为子进程先运行)。
结束子进程:
exit和_exit函数用于正常终止一个程序,_exit()立即进入内核,exit()则需要先执行一些清除处理(包括调用执行各终止处理程序,关闭所有标准I/O流等),然后再进入内核。
结束子进程不用exit(0),而使用_exit(0)。因为_exit(0)在结束进程时,不对标准I/O流进行任何操作,而exit(0)回关闭进程的所有标准I/O流