fork()和vfork()函数

fork是一个很重要的函数,能否彻底理解父子进程的关系,取决于你对fork的理解的程度。

#include<unsitd.h>
pid_t fork(void)

从书上我总结了三点:

  1. fork调用一次返回两次,子进程返回0,父进程返回子进程ID

  2. 父子进程共享正文段,拥有父进程数据段,堆和栈的副本

  3. 对于第二点的父进程的数据段,堆,栈,fork采用一种写时复制技术,需要的时候才复制一个副本

看一个如下的程序:

#include <apue.h>
int glob = 6;
char buf[] = "a write to stdout";
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("brfore fork\n");
	if((pid = fork()) < 0)
		err_sys("fork error\n");
	else if(pid == 0)
	{
		glob++;
		var++;
	}
	else
		sleep(2);
	printf("pid=%d,ppid=%d,glob=%d,var=%d\n",getpid(),getppid(), glob, var);
	exit(0);

}

vfork函数:

#include <sys/types.h>
#include <unistd.h>
pid_t vfork(void);

vfork:createa child process and block parent

1.vfork的目的是exec一个新程

2.vfork保证子进程先运行,在它调用execexit之后父进程才可能被调度运行

看一个程序:

#include <apue.h>
int glob = 6;
int main(void)
{
    int var = 88; 
    pid_t pid;
    printf("before vfork\n");
    if((pid = vfork())<0)
        err_sys("vfork error");
    else if(pid == 0)
    {   
        glob++;
        var++;
        printf("before parent!\n");
        _exit(0);
    }   
    /*parent continue here*/

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

接下来,我们在理解另外两个概念:

init进程:

进程ID1,在系统自举过程结束时由内核调用,该进程不会终止

如果一个进程的父进程已经终止,那么该进程会被init进程领养

僵尸进程:

一个已经终止,但是其父进程尚未对其处理的进程

看一个程序:

#include <apue.h>
#include <sys/wait.h>

int main(void)
{
    pid_t pid;
    if((pid=fork()) < 0)
        err_sys("fork error\n");
    else if(pid == 0)
    {   
        if((pid=fork()) < 0)
            err_sys("fork error");
        else if(pid > 0)
        {   
    
            printf("first child pid=%d ppid=%d\n",getpid(),getppid());
            exit(0);
        }   

        sleep(2);
        printf("seccond child,parent pid=%d\n",getppid());
        printf("second child pid=%d\n",getpid());
        exit(0);
    }
    if(waitpid(pid,NULL,0) != pid)
        err_sys("waitpid error\n");
    printf("parent pid=%d ppid=%d\n",getpid(),getppid());
    exit(0);
}

这个程序融合了上面的两个概念:

  1. 这个程序调用了fork两次,且第二次使第一个子进程终止了,父进程调用了waitpid(由于受到子进程终止时,内核发送的SIGCHILD信号而调用),所以第一进程不会成为僵尸进程

  2. 第二个子进程在它的父进程终止后会被init进程领养




你可能感兴趣的:(编程,unix,fork)