UNIX环境高级编程第8章进程控制 8.3fork 文件共享 vfork

%H]1)K)(G[IRIQ0VLVRRGPQ

进程ID为0的进程通常是调度进程,常常被称为交换进程swapper,该进程是内核的一部分,这并不执行任何磁盘上的程序,因此也被称为系统进程,进程ID为1是init进程,在自举过程结束时由内核调用,该进程的程序文件为/etc/init或者/sbin/init,此进程负责在自举内核后启动一个UNIX系统。init通常读取与系统相关的初始化文件/etc/rc*文件,或/etc/inittab文件,以及/etc/init.d中的文件。并将系统引导到一个状态(例如多用户)。init决不会终止,它是一个普通的用户进程(与交换进程不同,它不是内核中的系统进程),但是它以超级用户运行,它是所有孤儿进程的父进程。

进程ID2是页守护进程pagedaemon,负责支持虚拟存储系统的分页操作。

BC[C]TS`7DSGT_7(]C)W22X

AISI`7`N@G6ZB]3OZB~B%CG

O81DVT6TM(MZC89]M_IZA2S

Q_6P%{LAEZ%H2T`50Y_XM[2

一个现有进程可能通过调用fork创建一个新进程,新进程称为子进程,fork函数调用一次返回两次,再次返回的唯一区别是,子进程返回值是0,父进程的返回值是子进程ID。

子父进程继续执行fork调用之后的指令。子进程是父进程的副本,子获得父进程数据空间,堆和栈的副本。子父并不共享,因为子复制了父的这些存储空间。父子共享正文段。

//以下来自网络

对于exec系列函数
    一个进程一旦调用exec类函数,它本身就“死亡”了,系统把代码段替换成新的程序的代码,废弃原有的数据段和堆栈段,并为新程序分配新的数据段与堆栈段,唯一留下的,就是进程号,也就是说,对系统而言,还是同一个进程,不过已经是另一个程序了。不过exec类函数中有的还允许继承环境变量之类的信息,这个通过exec系列函数中的一部分函数的参数可以得到

对于exec():
1、进程调用exec()后,将在同一块进程内存里用一个新程序来代替调用
  exec()的那个进程,新程序代替当前进程映像,当前进程的“数据段”,
“堆栈段”和“代码段”背新程序改写。
2、新程序会保持调用exec()进程的ID不变。
3、调用exec()之前打开打开的描述字继续打开(好像有什么参数可以令打开
  的描述字在新程序中关闭)

//以上来自网络

// proc/fork1.c 8-1
#include "apue.h"

int glob = 6; /* external variable in initialized data */
char buf[] = "a write to stdout
";

int main(void)
{
    int var; /* automatic variable on the stack */
    pid_t pid;

    var = 88;
    if (write(STDOUT_FILENO, buf, sizeof(buf)-1) != sizeof(buf)-1)
        err_sys("write error");
    printf("before fork

"); /* we don't flush stdout */
    /* fflush(stdout); */           /* if comments this line, the child will flush the stdout */

    if ((pid = fork()) < 0)
    {
        err_sys("fork error");
    }
    else if (pid == 0)
    {
                                              /* child, first flush buffer */
        printf("hello, I am child process
");
        glob++;                               /* modify variables */
        var++;
    }
    else
    {
        sleep(3);                             /* parent */
        printf("hello, I am parent process
");
    }

    if (0 == pid) /* for the child process, variable pid is 0 */
    {
        printf("hello, I am child process, variable pid is 0
");
    }
    else          /* for the parent process, variable pid is child pid */
    {
        printf("hello, I am parent process, variable pid is child pid
");
    }
    printf("pid = %d, pid = %d, glob = %d, var = %d


", pid, getpid(), glob, var);

    return 0;
}
all: shell1 shell2 fork1
shell1: shell1.c
	g++ -g -Wall shell1.c ../lib/libapue.a -I ../include -o shell1
shell2: shell2.c
	g++ -g -Wall shell2.c ../lib/libapue.a -I ../include -o shell2
fork1: fork1.c
	g++ -g -Wall fork1.c ../lib/libapue.a -I ../include -o fork1
clean:
	rm shell1 shell2 fork1

image

交互式的方式执行fork1,在子进程创建之前,before fork已经被父进程从缓冲区刷新,before fork已经被输出到终端设备(交互式是行缓冲),而采用重定向到磁盘文件的方式,这种情况是全缓冲的,也就是说,before fork还在缓冲区,这个缓冲区又被复制到了子进程,于是子进程缓冲区被刷新时,before fork在子进程终止时,被输出了出来。

在重定向父进程的标准输出时,子进程的标准输出同样被重定向,这点还是有疑惑

JL$PZOR9~3N$`Z6SC`6B(5X

CON274UC~$$Z{3W)QLBJ(4L

RWRYTCPV5CU]KV{}H~UW`BC

H9JF[)E5K5A%HK8`1VKI9FM

A7F~37(Y)67%OETXUMG22L9

1VMN9[GZ%%7XV{AO{%2WD_G

vfork用于创建一个新进程,该进程的目的是exec一个新进程,但是它不将父进程的地址空间完全复制到子程序,因为子会立即调用exec,或者exit,于是也就不会访问该地址空间,在调用exec之前,子在父进程的空间运行,且vfork保证子进程先运行,在子调用exec或exit之后,父才可能被调度运行。

// proc/vfork1.c 8-2
#include "apue.h"

int glob = 6; /* external variable in initialized data */

int main(void)
{
    int var; /* automatic variable on the stack */
    pid_t pid;

    var = 88;
    printf("before vfork
"); /* we don't flush stdio */
    if ((pid = vfork()) < 0) 
    {
        err_sys("vfork error");
    }
    else if (pid == 0)
    {   /* child */
        // vfork ensure the child will go first, parent will not continue untill the child run function exec or exit, no matter how long the parent has to wait
        glob++; /* modify parent's variables */
        var++;
        printf("I'm child, I am going to sleep 5 second
");
        sleep(5);
        printf("I'm child, I am going to invork exit function
");
        _exit(0); /* child terminates */
    }

    /*
     * Parent continues here.
     */
    printf("parent print: pid = %d, glob = %d, var = %d
", getpid(), glob, var);
    return 0;
}
all: shell1 shell2 fork1 vfork1
shell1: shell1.c
	g++ -g -Wall shell1.c ../lib/libapue.a -I ../include -o shell1
shell2: shell2.c
	g++ -g -Wall shell2.c ../lib/libapue.a -I ../include -o shell2
fork1: fork1.c
	g++ -g -Wall fork1.c ../lib/libapue.a -I ../include -o fork1
vfork1: vfork1.c
	g++ -g -Wall vfork1.c ../lib/libapue.a -I ../include -o vfork1
clean:
	rm shell1 shell2 fork1 vfork1

OH@[C{}75S8E(ETAED)YPA3

%M@%EX{I7KJ[N1%6ZUZ{292

V]]R_EM0`X9~HND{RO3~EI0

@GD}UZC1NB7WWX8N@VRN_~L

bf6c75b6a68ac3d3b78126e1528bbaac

原文地址:https://www.cnblogs.com/sunyongjie1984/p/4262769.html