zoukankan      html  css  js  c++  java
  • return, exit, _exit的区别

    return是返回的最常用的方式

    _exit属于POSIX定义的系统调用

    exit是GLIBC封装之后的函数

    1 _exit和exit都会导致整个进程退出,清理进程所占用的资源,但是glibc封装exit函数的时候加了一些功能:比如提供了在结束程序时回调的接口(atexit), flush 缓冲区(系统调用是没法做这个的

    ,因为像printf, scanf之类的缓冲区都属于应用层缓冲区,内核清理资源自然无法顾及)

    2return 会清理函数栈,另外两个就不会了,如果是最后一个线程return,也会像exit那样清理资源并flush缓冲区,这一点可以通过一段代码观察一下:

      

     1 #include<iostream>
     2 #include<unistd.h>
     3 using namespace std;
     4 
     5 class A
     6 {
     7 public:
     8     A(){
     9         cout << "constructor" << endl;
    10     }
    11     ~A(){
    12         cout << "distructor" << endl;
    13     }
    14 };
    15 void func(int i)
    16 {
    17     A a;
    18     if(i == 0)
    19         _exit(-1);
    20     else
    21         return;
    22 }
    23 
    24 int main()
    25 {
    26     func(1);
    27     return 0;
    28 }

    这里可以发现,只有按照return 方式返回局部变量a的析构函数才能得到调用,因为exit _exit都是不清理函数栈的.

    一般这不会有什么问题,因为资源都回收了,栈空间自然也没了.但是对于约定在函数返回时调用的函数就没法调用了.

    还有一点要注意的是,全局变量并不在栈空间里面,对于C++的情形而言,可以在全局变量的构造函数中申请资源然后

    在程序结束的时候由析构函数释放.这个过程事实上是通过在函数启动的时候插入全局变量的构造函数,函数退出的地方插入

    析构函数做到的.所以,即使是调用exit,全局变量仍旧可以正常析构. 但是_exit就不一样了,仍旧不会释放(_exit属于系统

    调用,它只管内核空间中的一些资源释放)

    #include<iostream>
    #include<unistd.h>
    using namespace std;
    
    class A
    {
    public:
        A(){
            cout << "constructor" << endl;
        }
        ~A(){
            cout << "distructor" << endl;
        }
    };
    void func(int i)
    {
        A a;
        if(i == 0)
            _exit(-1);
        else
            return;
    }
    A ta;
    int main()
    {
        A a;
        _exit(0);
    }

     3关于vfork的问题

    #include<unistd.h>
    #include<stdio.h>
    int glovalvar = 9;
    
    int main()
    {
        int var = 88;
        pid_t pid;
        printf("before vfork
    ");
        if((pid = vfork()) < 0)
        {
            fprintf(stderr, "vfork error");
            return 0;
        }
        else if(pid == 0)
        {
             glovalvar++;
             var++;
             _exit(0);
        }
        else
        {
    
        }
        printf("pid = %ld, glob=%d, var=%d
    ", (long)getpid(), glovalvar, var);
        return 0;
    }

    这是apue上面的一段示例代码,很惊奇的发现居然可以在子进程中访问到局部变量var,这意味着什么??要知道单一进程内
    ,如果出现函数调用,过程是这样的:

    1返回地址压栈

    2参数压栈

    3保存当前的ebp

    在程序中写一个return意味着什么???思考一下,其实是要清理当前的函数栈的,C语言的情形下比较好想,反正栈指针退到指定位置就好

    c++中却还要在返回之前调用局部变量的析构函数

    最最重要的是,即使是像c语言那样简单的将栈指针回退,在vfork的情形下,也会出问题:

    回退到哪??前面已经说过了,返回地址处(也就是当前函数的调用点)!

    可以想象,这里所说的在父进程空间运行多么图省事,连一个单独的函数调用的开销都不肯付出(如果有子过程调用,那局部变量不可能访问得到)

    直接就用了父进程main函数的函数栈, 你一个return,它直接把栈指针指到了main函数调用点,简单来说,就是main函数的函数栈被清理了,那切换到父进程就莫名奇妙了!

    而如果是exit或_exit,则进程直接退出了,对于用户空间的函数栈根本不理会(具体来说就是ebp, esp寄存器的值)

    所以不会出现问题.

  • 相关阅读:
    javascript命名空间的简单实现
    javascript变量的作用域
    Python单元测试框架
    opencv中遍历图片数据的两种方法
    hsv 与 hsi 颜色空间
    OpenCV资料
    Linux下查看文件和文件夹大小
    The run destination iPhone 5.0 Simulator is not valid for running the scheme 'MyApp'
    OpenCV函数学习之cvLUT
    Linux中find常见用法示例
  • 原文地址:https://www.cnblogs.com/hustxujinkang/p/4992949.html
Copyright © 2011-2022 走看看