zoukankan      html  css  js  c++  java
  • 回收进程用户空间资源 exit()函数 _exit()函数 atexit()函数 on_exit()函数

    摘要:本文主要讲述进程的终止方式,以及怎样使用exit()函数来终止进程。回收进程用户空间资源;分析了exit()函数与_exit()函数,returnkeyword的差异.同一时候具体解读了怎样使用atexit()和on_exit()函数来注冊终止处理程序.

    进程终止、回收资源

    1.进程终止方式

        在内核中,程序运行的唯一方法是调用一个exec函数.而进程自愿终止的唯一方法是显示或隐式地调用_exit()或_Exit().
        进程有5种正常终止方式:
    (1)常见的一种是,在main函数中运行return语句,这点是等效于调用exit().
    (2)调用exit()函数,其操作包含调用终止处理程序(由atexit()或on_exit()函数注冊,下文再细细说来)。然后关闭全部IO流等.
    (3)调用_exit或_Exit函数.
    (4)进程的最后一个线程在其启动例程中运行返回语句.可是,该线程的返回值不会用作进程的返回值.当最后一个线程从其启动例程返回时。该进程以终止状态0返回.
    (5)进程的最后一个线程调用pthread_exit函数.
         3种异常终止方式:(在这里仅仅做了解,不细细讨论).
    (6)调用abort.它产生SIGABRT信号,这个终止方式依靠信息传递机制.
    (7)当进程接收到某些信号时,信号可由进程自身、其它进程或内核产生.
    (8)最后一个线程对“取消”请求作出响应.
        无论进程是怎样终止。最后都会运行内核中的同一段代码.关闭全部文件描写叙述符,释放他全部的存储器等等.如:进程正常退出前须要运行注冊的退出处理函数(终止处理程序),刷新流缓冲区等操作,然后释放进程用户空间.而进程控制块PCB并不在这时释放.仅调用退出函数的进程属于一个僵死进程.
        僵死进程:在UNIX系统中。一个已经终止,可是其父进程尚未对其进行善后处理(获取终止子进程的信息,释放所占资源)的进程称为僵死进程.

    2.exit()与return的差别

        函数exit()用于退出进程.在正式释放资源前,将以反序的方式运行由on_exit()函数和atexit()函数注冊的清理函数(终止处理程序)。同一时候刷新流缓冲区.C语言keywordreturn与exit()在main函数(注意:仅仅是在main函数。在其它地方,是不相同的)中完毕相同的操作。但两者有本质的差别:
    (1)return退出当前函数,exit()函数退出当前进程;因此,在main函数里。return(0)和exit(0),完毕一样的功能.
    (2)return仅从子函数中返回,并不退出进程.调用exit()时要调用一段终止处理函数,然后关闭全部的IO流.以下的样例1是专门讲述这点差异的.

    3.exit()函数

    头文件:#include <stdlib>
    定义函数:void exit(int status);
    函数说明:
        exit()函数用来正常终止眼下进程的运行,并把參数status(称之为终止状态)返回给父进程,而进程全部的缓冲区数据自己主动写回并关闭全部IO流.
    样例1:在main函数使用死循环的方式调用子函数fun().在这个样例能够看到exit和return的差异.
    #include <stdio.h>
    #include <unistd.h>
    #include <stdlib.h>
    int fun()
    {
            printf("fun
    ");
            sleep(1);
    
            //读者切换调用,体会一下
            //return 0;
            exit(0);
    }
    
    int main()
    {
            int i;
            i++;
            printf("i = %d 
    "。i);
            while(1)
                    fun();
            return 0;
    }
    

       

        在上面这个样例中,我们看到假设在子函数中使用exit(),则循环仅仅运行一次。假设在子函数中使用returnkeyword,则死循环将一直运行下去.

    4._exit()函数

    头文件:#include <unistd.h>
    定义函数:void _exit(int status);
    函数说明:
        _exit()等价于_Exit().
        _exit()函数用来马上结束程序的运行,并把參数返回给父进程。不调用不论什么终止处理程序而直接退出.此函数调用后不会返回。而且会传递SIGCHLD信号给父进程。父进程能够由wait()函数取得子进程结束的状态.注意:_exit()不会处理标准IO缓冲区,假设更新缓冲区请使用exit().
    样例2:查看exit与_exit函数的差别.
    #include <stdlib.h>
    #include <stdio.h>
    #include <unistd.h>
    int main()
    {
            printf("output
    ");
            printf("content int buffer"); //不带
    
    
            //_exit(0);             //仅仅输出output。没有清理缓冲区(没刷新)
            exit(0);                //改为此句,将输出content int buffer
            //return 0;
    }

       

        由样例2能够看出。_exit()调用退出时,没有清理刷新缓冲区.终止一个程序时,_exit()马上进入内核,而exit()则先要运行一些清理处理程序.

    5.atexit()和on_exit()函数

    头文件:#include<stdlib.h>
    定义函数:
    int atexit(void (*function)(void));
    int on_exit(void (*function)(int 。 void *), void *arg);
    返回值:如成功返回0,若出错返回非0值.
    函数说明:
        函数atexit()和on_exit()用来注冊运行exit()函数前运行的操作函数。事实上现使用了回调函数的方法.按ISO C规定。一个进程能够注冊多达32个函数,这些函数被称之为终止处理程序.查看实际能够注冊多少个终止处理程序,能够通过调用sysconf()函数获得.exit()调用这些函数的顺序与他们登记时候的顺序相反.同一个函数如若登记多次,则也会被调用多次.函数atexit()和on_exit()两者的差异不过在函数的參数上.
        当中atexit()函数的參数是一个函数的地址,类型为void (*function)(void);当调用此函数时无需向它传递不论什么參数,也不期望它返回一个值.
        而on_exit()函数的參数是一个带參数的函数。类型为void (*function)(int , void *),在这个函数void (*function)(int , void *)中。第一个參数为退出的状态,在运行exit()函数时传递此參数值为exit()函数的參数.第二个參数为用户输入信息,一个无类型的指针。用户能够指定一段代码位置或输出信息.(这里有点拗口,结合以下的样例3看看.)
    样例3:说明怎样使用atexit()函数.
    #include <stdlib.h>
    #include <stdio.h>
    #include <unistd.h>
    static void my_exit1();
    static void my_exit2();
    
    int main()
    {
            int i=0;
            if(atexit(my_exit2)!=0)
            {
                    printf("can't register my_exit2");
            }
            for(i=0; i<3; i++)
            {
            if(atexit(my_exit1)!=0)
                    {
                            printf("can't register my_exit1");
                    }
            }
    
            printf("main exiting....
    ");
            return 0;
            //exit(0);//同return 0;
            //_exit(0);//这个就不同了
    }
    
    static void my_exit1()
    {
            printf("first exit handler...
    ");
    }
    static void my_exit2()
    {
            printf("second exit handler...
    ");
    }
    


    输出:

    :main exiting....
    :first exit handler...
    :first exit handler...
    :first exit handler...
    :second exit handler...

        终止处理程序每注冊一次。就会被调用一次.在上述样例中,第一个终止处理程序被注冊了3次。所以也会被调用3次.且调用顺序是和注冊时的顺序是相反的,这让我们联想到栈的原理,先进后出,后进先出.
        注意:这里在main函数是调用return 0(和exit()一样),可是假设调用_exit(),输出结果就不一样了.程序仅仅会输出main exiting.....由于_exit()不会去调用清理工作的函数.
    样例4:说明怎样使用on_exit()函数.
    #include <stdio.h>
    #include <stdlib.h>
    
    static void test_exit(int status,void *arg);
    
    int main()
    {
            char *str = "How to use on_exit function...
    ";
            on_exit(test_exit,(void *)str);
            exit(1314);
            //return 520;
    }
    static void test_exit(int status,void *arg)
    {
            printf("before exit()!
    ");
            printf("exit:%d
    "。status);
            printf("arg=%s
    "。(char *)arg);
    }


    输出:

    :before exit()!
    :exit:1314
    :arg=How to use on_exit function...

        能够看出。on_exit()和exit()还有终止处理程序test_exit()之间的关系.函数test_exit()的两个參数都是从“别人”哪里得来的.注意了。这里假设是用return 520;效果也会一样哦,读者能够试试.
    样例5:在终止处理程序中调用_exit()函数,这个有点奇葩啊,读者猜想一下会是神马结果呢.改良样例4,得到下面程序:
    #include <stdlib.h>
    #include <stdio.h>
    #include <unistd.h>
    static void my_exit1();
    static void my_exit2();
    static void my_exit3();
    
    int main()
    {
            int i=0;
            if(atexit(my_exit2)!=0)
            {
                    printf("can't register my_exit2
    ");
            }
    		 //新添加的部分
            if(atexit(my_exit3)!=0)
            {
                    printf("can't register my_exit3
    ");
            }
            for(i=0; i<3; i++)
            {
            if(atexit(my_exit1)!=0)
                    {
                            printf("can't register my_exit1
    ");
                    }
            }
    
            printf("main exiting....
    ");
            //return 0;
            exit(0);
            //_exit(0);
    }
    
    static void my_exit1()
    {
            printf("first exit handler...
    ");
    }
    static void my_exit2()
    {
            printf("second exit handler...
    ");
    }
    static void my_exit3()
    {
            printf("three exit handler...
    ");
            _exit(0);//注意这里了.加了_exit(0);
    }


    输出:

    : main exiting....
    :first exit handler...
    :first exit handler...
    :first exit handler...
    :three exit handler...

        发现没有,“second exit handler...”这个没有输出,为什么?假设在当中一个终止处理程序中(atexit() or on_exit())调用了_exit()函数。那剩余的终止处理程序将不会得到调用。同一时候由exit()函数调用的其它终止进程步骤也将不会运行.

    6.综述

        exit()退出会处理缓冲区。_exit()不会.资源不能浪费,分配出去的资源,要记得回收回来,给更须要的进程使用.不要站着茅坑不拉屎.
        atexit()和on_exit()注冊终止处理程序。假设用户在结束进程前,想干一下别的事。能够用这两个函数注冊.
        exit()和return等价,仅在main函数中.

        _exit()和_Exit()等价,不论什么时候.

    參考阅读:

    [1] exit()函数使用说明.http://blog.csdn.net/u010006102/article/details/39737155.

    [2] _exit()函数使用说明.http://blog.csdn.net/u010006102/article/details/39740101.

    [3] atexit()函数使用说明.http://blog.csdn.net/u010006102/article/details/39740071.

    [4] on_exit()函数使用说明.http://blog.csdn.net/u010006102/article/details/39740021.


    笔者:个人能力有限,仅仅是学习參考...读者若发现文中错误,敬请提出.

    ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------勿在浮沙筑高台,静下心来。慢慢地沉淀---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  • 相关阅读:
    Programmatically parsing Transact SQL (TSQL) with the ScriptDom parser
    How to check for a valid Base64 encoded string
    三角函数和反三角函数
    Preventing User Enumeration on Registration Page
    创建HyperV虚拟机安装Win10教程详解
    爆强,看看PS高手怎么变出一个美女来
    用baidu搜索“sb”会出来什么结果?baidu也太狠了吧
    一组Opeth(月亮之城)的现场视频
    为了节约成本,要在西游记团队中栽一个你会裁掉哪位?
    Ruby on rails开发从头来(windows)(四)第一个添删查改例子
  • 原文地址:https://www.cnblogs.com/zfyouxi/p/5204052.html
Copyright © 2011-2022 走看看