10 October 2016
版权声明:本文基于署名 2.5 中国大陆许可协议发布,欢迎转载,演绎或用于商业目的,但是必须保留本文的署名elloop(包含链接)

前言

本文是APUE第四章:文件和目录知识点的总结和代码实践的总结。

关键点

  • fork

  • vfork

  • exit

  • exec系列

  • wait, waitpid, waiid

实践代码

process_controll.cpp

#include "include/inc.h"
#include "include/apue.h"
#include <string>
using std::string;

NS_BEGIN(elloop);


// demonstrate sub-process holds a copy of parent process.
int globalVar = 100;
BEGIN_TEST(ProcessControll, Fork, @@);

string buff("content from buff\n");

int localV = 1;
ERR_IF(write(STDOUT_FILENO, buff.c_str(), buff.length()) != buff.length(), err_ret, "fail to write buff");

// printf("before fork!");
printf("before fork!\n");    // \n will flush stdout.

// fflush(STDOUT_FILENO);       // fflush(FILE*), not fd.
// fflush(stdout);              // flush stdout so the "before fork" won't be copied into sub-process.

pid_t pid(0);
if ((pid = fork()) < 0) {
    err_sys("fail to fork");
}
else if (pid == 0) {
    // child process.
    ++globalVar;
    ++localV;
}
else {
    // > 0, parent process.
    sleep(2);
}

printf("pid: %ld, globalVar: %d, localV: %d\n", (long)getpid(), globalVar, localV);

END_TEST;


int globalVar2 = 10;
BEGIN_TEST(ProcessControll, Vfork, @@);

int localV = 1;
printf("before vfork!\n");
pid_t pid(0);
if ((pid = vfork() ) < 0) {
    err_sys("fail to vfork");
}
else if (pid == 0) {
    // child
    ++globalVar2;
    ++localV;
    _exit(0);
    // exit(0);        // 60338 Segmentation fault: 11
}

printf("pid: %ld, globalVar2: %d, localV: %d\n", (long)getpid(), globalVar2, localV);
// pid: 60416, globalVar2: 11, localV: 2

END_TEST;

void printExit(int status) {
    if (WIFEXITED(status)) {
        printf("normal termination, exit status = %d\n", WEXITSTATUS(status));
    }
    else if (WIFSIGNALED(status)) {
        printf("abnormal termination, signal number = %d%s\n", WTERMSIG(status),
#ifdef WCOREDUMP
                WCOREDUMP(status) ?  " (core file generated)" : "");
#else
                "");
#endif
    }
    else if (WIFSTOPPED(status)) {
        printf("child stopped, signal number = %d\n", WSTOPSIG(status));
    }
}

BEGIN_TEST(ProcessControll, ExitStatus, @@);

pid_t pid;
int st;

pid = fork();
ERR_IF_NEG(pid, err_sys, "fail to fork");
if (pid == 0) {
    exit(7);
}
ERR_IF(wait(&st) != pid, err_sys, "wait error");
printExit(st);

pid = fork();
ERR_IF_NEG(pid, err_sys, "fail to fork");
if (pid == 0) {
    abort();
}
ERR_IF(wait(&st) != pid, err_sys, "wait error");
printExit(st);


pid = fork();
ERR_IF_NEG(pid, err_sys, "fail to fork");
if (0 == pid) {
    st /= 0;
}
ERR_IF(wait(&st) != pid, err_sys, "wait error");
printExit(st);

END_TEST;

BEGIN_TEST(ProcessControll, Waitpid, @@);

pid_t pid;
pid = fork();
ERR_IF_NEG(pid, err_sys, "fail to fork");
if (0 == pid) {
    // first child
    pid = fork();
    ERR_IF_NEG(pid, err_sys, "fail to fork");
    if (pid > 0) {
        exit(0);    // first child terminate.
    }

    // second child continuing... will be inherited by init process.
    sleep(2);
    printf("parent pid: %ld\n", (long)getppid());
    exit(0);
}

// parent process, wait for the first child.
ERR_IF(waitpid(pid, NULL, 0) != pid, err_sys, "waitpid error");     // NULL means don't care about the termination status of the child process.
exit(0);

END_TEST;


BEGIN_TEST(ProcessControll, RaceCondition, @@);

auto printChar = [](char* str) {
    char*   ptr;
    int     c;
    setbuf(stdout, NULL);
    for (ptr = str; (c = *ptr++) !=0; ) {
        putc(c, stdout);
    }
};

pid_t pid;
pid = fork();
ERR_IF_NEG(pid, err_sys, "fail to fork");
if (0 == pid) {
    printChar("print char in child process\n");
}
else {
    printChar("print char in parent process\n");
}

END_TEST;


RUN_GTEST(ProcessControll, Exec, @@);

pid_t pid;
pid = fork();
ERR_IF_NEG(pid, err_sys, "fail to fork");

const char    *envInit[] = {"USER=nonono", "PATH=/tmp", NULL};
if (0 == pid) {
    int ret = execle("/Users/elloop/codes/temp/echoall", "echoall-elloop", "arg1", "arg-2", (char*)0, envInit);
    ERR_IF_NEG(ret, err_sys, "execle error");
}

ERR_IF_NEG(waitpid(pid, NULL, 0), err_sys, "wait error");

pid = fork();
ERR_IF_NEG(pid, err_sys, "fail to fork");
if (0 == pid) {
    int ret = execlp("echoall", "echoall-arg0", "only 1 arg", (char*)0);
    ERR_IF_NEG(ret, err_sys, "execlp error");
}

END_TEST;

NS_END(elloop);

错误总结

/*
 * error committed:
 *
 *      1. use int as pid type. 
 *          should be pid_t.
 *
 *      2. use (pid>0) as the fork() and vfork() return value to the child process.
 *          should be (pid == 0) to the child process.
 *
 *      3. use getpid() to get parent pid in Waitpid test case.
 *          should use getppid().
 *
 *      4. RaceCondition test case, don't act as book say. there is no intermixing of output from the two processes.
 *          should be tested in single core cpu machine.
 */


作者水平有限,对相关知识的理解和总结难免有错误,还望给予指正,非常感谢!

在这里也能看到这篇文章:github博客, CSDN博客, 欢迎访问



分享到