zoukankan      html  css  js  c++  java
  • UNIX环境高级编程8.5exit 8.6wait waitpid

    RP`%K8$$U[0PR%9_{$EK10B

    不管进程如何终止,最后都会执行内核中的同一段代码,为相应的进程关闭所有打开描述符,释放它所使用的存储器。无论进程如何终止,我们都希望该进程能够通知其父它是如何终止的,对于exit,_exit,_Exit(一种情况),将其退出状态作为参数传送给函数(exit(3)),对于异常终止(另一种情况),内核产生一个指示其异常终止原因的终止状态。这两种情况,该进程父进程都能用wait或waitpid函数取得其终止状态。

    退出状态与终止状态有所区别。

    OERLPJ_F}PY_$3)4`P)MU60

    X[A~Q(TIDC48S)YCEUBH8J1

    僵死进程是,一个已经终止,但是其父进程尚未对其进行善后处理(获取终止子进程的有关信息,释放它仍占用的资源)的进程。

    当一个进程正常或异常终止时,内核向父进程发送SIGCHLD信号,该信号是内核向父进程发的异步通知,父进程可以忽略它,也可定义一个函数(信号处理程序)来处理这个信号。默认是忽略。父调用wait/waitpid时:

    1. 如果其所有子进程都在运行,则阻塞。
    2. 如果一个子终止,则父取得子终止状态,父wait或者waitpid立即返回。
    3. 如果父没有任何子,立即返回。

    如果父由于接到SIGCHLD而调用wait,则可期待wait立即返回。

    waitpid可选择等待终止的子进程。

    YVPHH3INE[AS(QX{5A]OOP1

    O4S]D}1SHO9_WZ4DZQR`@U5

    进程终止状态在<sys/wait.h>/usr/include/sys/wait.h

    UNIX系统信号

    LSR02JIO9C11IE2))}}N)GU

    [BVO_[T8BA)BUI1Z4{R(NK2

    signum.h

    @QAVW`[N}A3TY]G}%UN@3`N

    如果一个子进程已经终止,并且是一个僵死进程,则wait立即返回并取得该子进程状态(就是说父调用wait的时候,其儿子中已经有一个是僵死进程了,因为子终止之前,父没有调用wait,并进行收尸工作),否则wait阻塞到任一子进程终止。

    TXWDDI7A6PJT[RM1LD75[MT

    // proc/wait1.c 8-4
    #include "apue.h"
    #include <sys/wait.h>
    
    int main(void)
    {
        pid_t pid;
        int status;
    
        if ((pid = fork()) < 0)
            err_sys("fork error");
        else if (pid == 0) /* child */
            exit(7); // terminate normally
    
        if (wait(&status) != pid) /* wait for child */
            err_sys("wait error");
        pr_exit(status); /* and print its status */
    
        if ((pid = fork()) < 0)
            err_sys("fork error");
        else if (pid == 0) /* child */
            abort(); /* generates SIGABRT */
    
        if (wait(&status) != pid) /* wait for child */
            err_sys("wait error");
        pr_exit(status); /* and print its status */
    
        if ((pid = fork()) < 0)
            err_sys("fork error");
        else if (pid == 0) /* child */
            status /= 0; /* divide by 0 generates SIGFPE */
    
        if (wait(&status) != pid) /* wait for child */
            err_sys("wait error");
        pr_exit(status); /* and print its status */
    
        return 0;
    }
    
    // lib/prexit.c
    #include "apue.h"
    #include <sys/wait.h>
    
    void pr_exit(int status)
    {
        // two condition of a process terminate:
        // 1, child invoke exit.
        // 2, child terminate abnormally.
        if (WIFEXITED(status)) // exited
            printf("normal termination, exit status = %d
    ",
                    WEXITSTATUS(status));
        else if (WIFSIGNALED(status)) // signaled, and parent has no function handle this signal
            printf("abnormal termination, signal number = %d%s
    ",
                    WTERMSIG(status),
    #ifdef WCOREDUMP
                    WCOREDUMP(status) ? " (core file generated)" : "");
    #else
        "");
    #endif
        else if (WIFSTOPPED(status))
            printf("child stopped, signal number = %d
    ",
                    WSTOPSIG(status));
    }
    
     
    all: shell1 shell2 fork1 vfork1 wait1
    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
    wait1: wait1.c
    	g++ -g -Wall wait1.c ../lib/libapue.a -I ../include -o wait1
    clean:
    	rm shell1 shell2 fork1 vfork1 wait1

    H`UU`A0MF0DJ3COYXJ2JE5E

    ~P$883%5}UB{9JT3UN~T6KV

    调用fork两次以避免僵死进程

    S0[2RCRJ]MIA_L9I[V9WV]G

    // proc/fork2.c 8-5
    #include "apue.h"
    #include <sys/wait.h>
    
    int main(void)
    {
        printf("file %s, line %d parent, getpid() = %d
    ", __FILE__, __LINE__, getpid());
        fflush(stdout);
        pid_t pid;
    
        if ((pid = fork()) < 0)
        {
            err_sys("fork error");
        }
        else if (pid == 0)
        { /* first child */
            printf("file %s, line %d first child, getpid() = %d
    ", __FILE__, __LINE__, getpid());
            fflush(stdout);
            if ((pid = fork()) < 0)
            {
                err_sys("fork error");
            }
            else if (pid > 0)
            {
                printf("first child, going to sleep(2)
    ");
                sleep(2);
                printf("first child, after sleep(2), begin exiting
    ");
                exit(0);   /* parent from second fork == first child */
            }
    
            /*
             * We're the second child; our parent becomes init as soon
             * as our real parent calls exit() in the statement above.
             * Here's where we'd continue executing, knowing that when
             * we're done, init will reap our status.
             */
            printf("file %s, line %d, child 2, getpid() = %d
    ", __FILE__, __LINE__, getpid());
            printf("second child, going to sleep(5)
    ");
            sleep(5);
            printf("second child, after sleep(5)
    ");
            printf("second child, parent pid = %d, parent id is 1, which means my parent process is init
    ", getppid());
            exit(0);
        }
    
        if (waitpid(pid, NULL, 0) != pid)  /* wait for first child */
            err_sys("waitpid error");
        else
            printf("after sleep(2), first child exit caught by parent (waitpid)
    ");
    
        printf("file %s, line %d, getpid() = %d
    ", __FILE__, __LINE__, getpid());
    
        /*
         * We're the parent (the original process); we continue executing,
         * knowing that we're not the parent of the second child.
         */
        exit(0);
    }
    
    all: shell1 shell2 fork1 vfork1 wait1 fork2
    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
    fork2: fork2.c
    	g++ -g -Wall fork2.c ../lib/libapue.a -I ../include -o fork2
    vfork1: vfork1.c
    	g++ -g -Wall vfork1.c ../lib/libapue.a -I ../include -o vfork1
    wait1: wait1.c
    	g++ -g -Wall wait1.c ../lib/libapue.a -I ../include -o wait1
    clean:
    	rm shell1 shell2 fork1 vfork1 wait1 fork2

    (@HGE7TT%QJD]~%_E~1EZ7O

    DN3`4_H[@ZAO09C{A5IYAXY

    c1d023af7670d89e5d997334d364d5ae

  • 相关阅读:
    HZNU 2019 Summer training 6
    HZNU 2019 Summer training 5
    HZNU 2019 Summer training 4
    Garlands CodeForces
    HZNU 2019 Summer training 3
    UVA
    HZNU 2019 Summer training 2
    Serge and Dining Room(线段树)
    HZNU 2019 Summer training 1
    【7-10 PAT】树的遍历
  • 原文地址:https://www.cnblogs.com/sunyongjie1984/p/4262982.html
Copyright © 2011-2022 走看看