【linux高级程序设计】(第八章)进程管理与程序开发 3

回收进程用户空间资源

仅调用退出函数的进程属于一个僵死进程,没有释放进程控制块PCB。

void exit (int __status):退出进程。会以反序执行on_exit()和atexit()中注册的清理函数,刷新流缓冲区。执行成功没有返回值,参数status用来标识退出状态返回给父进程;否则返回-1。

void _exit (int __status):不调用任何祖册函数和直接退出进程。此函数调用后不会返回,而是传递SIGCHLD信号给父进程,父进程可以通过wait函数获得子进程结束的状态。该函数不处理标准I/O缓冲区

int atexit (void (*__func) (void)):告诉进程,在正常退出时执行注册的func函数。注册函数没有参数

int on_exit (void (*__func) (int __status, void *__arg), void *__arg):告诉进程,在正常退出时执行注册的func函数。注册函数有参数,第一个参数为退出的状态,第二个参数为用户的输入信息。

exit与return区别:

(1)return退出当前函数,exit()退出当前进程。在main函数中return(0)和exit(0)完成一样的功能。

(2)return仅从子函数中返回,并不退出进程。而exit()在子函数中会调用终止处理程序,关闭所有I/O流。

#include<stdio.h>
#include<unistd.h>
#include<string.h>
int test(void)
{
    printf("a
");
    sleep(1);
    //exit(0);   //循环只执行一次
    return 0;   //死循环
}

int main(int argc, char * argv[])
{
    int i = 0;
    i++;
    printf("i=%d
",i);
    while(1)
        test();
    return 0;
}

exit与_exit使用对比

#include<stdlib.h>
int main(int argc, char * argv[])
{
    printf("output
");
    printf("content in buffer");   //注意没有回车,在缓冲区
    _exit(0);
}

_exit(0)只显示output

#include<stdlib.h>
int main(int argc, char * argv[])
{
    printf("output
");
    printf("content in buffer");   //注意没有回车,在缓冲区
    exit(0);
}

exit(0)显示output和content in buffer

on_exit使用例子:

#include<stdlib.h>
void test_exit(int status, void *arg)
{
    printf("before exit()!
");
    printf("exit %d
", status);
    printf("arg=%s
",(char*)arg);
}
int main()
{
    char *str="test";
    on_exit(test_exit,(void *)str);
    exit(4321);
}

回收内核空间资源

进程PCB的释放,由当前进程的父进程完成的。父进程可以显示的调用wait()waitpid()函数来完成。

__pid_t wait (__WAIT_STATUS __stat_loc):父进程阻塞式的等待该进程的任意一个子进程结束,回收子进程的内核进程资源。返回当前结束子进程的PID,退出状态存储在stat_loc中。

#define WIFSIGNALED(status)  __WIFSIGNALED(__WAIT_INT(status)) :宏,用来判断进程是否是因为收到信号后而退出的。如果是宏值为1.

#define WIFEXITED(status)   __WIFEXITED(__WAIT_INT(status)):宏,用来判断进程是否是正常退出的。如果是,宏值为1.

#include<stdio.h>
#include<unistd.h>
#include<sys/types.h>
#include<fcntl.h>
#include<string.h>
#include<stdlib.h>

extern int errno;
int main(int argc, char *argv[])
{
    pid_t pid_one, pid_wait;
    int status;
    if((pid_one = fork()) == -1)
        perror("fork");
    if(pid_one == 0)
    {
        printf("my pid is %d
", getpid());
        sleep(20);
        exit(EXIT_SUCCESS);   //正常退出
    }
    else
    {
        pid_wait = wait(&status);   //等待子进程结束
        if(WIFEXITED(status))
            printf("wait on pid: %d, normal exit, return value is:%4x
",pid_wait, WEXITSTATUS(status));
        else if(WIFSIGNALED(status))
            printf("wait on pid:%d, recive signal, return value is:%4x
", pid_wait, WIFSIGNALED(status));
    }
    return 0;
}

__pid_t waitpid (__pid_t __pid, int * __stat_loc, int __options):等待指定子进程结束

  第一个参数为进程PID值。

    PID > 0 :表示等待进程的PID就是PID

    PID == -1 :表示等待任意子进程结束,相当于调用wait函数

    PID == 0 :表示等待与当前进程的进程组PGID一致的进程结束

    PID < -1 :表示等待进程组PGID是此值的绝对值的进程结束

  第二个参数为结束进程的结束状态。

  第三个参数为等待选项,可设置为

    0 :阻塞

    WNOHANG  1 :不阻塞等待          没有子进程退出将返回0, 否则返回子进程的PID。

    WUNTRACED 2 :报告状态信息

孤儿进程与僵死进程

孤儿进程:父进程先退出,导致子进程被init进程收养的进程为孤儿进程。即父进程更改为init,init进程负责在孤儿进程退出后回收他的内核空间资源。

僵死进程:进程已经退出,但是父进程还没有回收其内核空间资源PCB

#include<stdio.h>
#include<unistd.h>
#include<stdlib.h>

int main()
{
    pid_t pid;
    if((pid = fork()) == -1)
        perror("fork");
    else if(pid == 0)
    {
        printf("child_pid pid = %d
", getpid());
    }
    sleep(3);
    system("ps");
    exit(0);
}

此时1184为僵死进程。

原文地址:https://www.cnblogs.com/dplearning/p/4679622.html