iOS exit函数深入浅出

2023-05-16

1.   exit函数

C,C++函数exit用来终止当前程序, 函数定义如下:

void exit (int status);


官方说明如下:

Terminates the process normally, performing the regular cleanup for terminating programs.
Normal program termination performs the following (in the same order):

  • Objects associated with the current thread with thread storage duration are destroyed (C++11 only).
  • Objects with static storage duration are destroyed (C++) and functions registered withatexit are called.
  • All C streams (open with functions in <cstudio>) are closed (and flushed, if buffered), and all files created with tmpfile are removed.
  • Control is returned to the host environment.
第三第四点比较容易理解就不展开讨论


第一点:

这里的thread storage指的是线程局部存储, 在线程作用域有效, c++11定义thread storage如下:

thread_local Object obj;  //Object为C++类
thread_local int value = 1;
第二点:
static storage指的是全局或者函数中static方式定义的变量, 该部分变量会存储到静态存储区(区别于heap和stack), 比如:
Object gObj;

void fun(){

  static Object sObj;

}

  
atexit设置的函数在exit过程中会被调用, atexit函数定义如下:
int atexit (void (*func)(void));
atexit例子如下:
/* atexit example */
#include <stdio.h>      /* puts */
#include <stdlib.h>     /* atexit */

void fnExit1 (void)
{
  puts ("Exit function 1.");
}

void fnExit2 (void)
{
  puts ("Exit function 2.");
}

int main ()
{
  atexit (fnExit1);
  atexit (fnExit2);
  puts ("Main function.");
  exit(0);
}
输出为:
Main function.
Exit function 2.
Exit function 1.

对C++ object销毁顺序, 可以看以下例子:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <thread>
#include <string>
#include <iostream>

class MyObject
{
public:
    std::string str;
public:
    MyObject(std::string str){
        this->str = str;
    }
    
    ~MyObject(){
        printf("%s -- %s\n", __FUNCTION__, str.c_str());
    }
};


void thread_fun(int n)
{
    thread_local MyObject threadObj("thread_local subthread  obj");
    //do something
    sleep(2);
}

void exit_fun(){
    MyObject threadObj("atexit obj");
    //do something
    sleep(1);
}

MyObject obj("global obj");
int main(int argc, const char * argv[])
{
    thread_local MyObject threadObj("thread_local mainthread  obj");
    static MyObject staticObj("fun static obj");
    std::thread t(thread_fun, 1);
    atexit(exit_fun);
    
    sleep(2);
    exit(0);
}

输出:
~MyObject -- thread_local subthread  obj 
~MyObject -- thread_local mainthread  obj
~MyObject -- atexit obj
~MyObject -- fun static obj
~MyObject -- global obj
Program ended with exit code: 0

从上面可以看出, 对于第二点是先调用atexit, 再清理static storage

2. exit vs abort


void abort (void);  

abort函数实际上是发送SIGABRT signal, 如果不处理则直接终止程序,此时并不会做cleanup操作,相当于直接终止程序。

3. IOS exit函数

双击Home 手动kill掉程序, 会调用exit函数关闭程序, __cxa_finalize函数会执行上面讲到清理工作。
如果重载了AppDelegate applicationWillTerminate函数,则在执行exit之前会调用该函数,终止前提供开发者程序处理机会。
如果程序已经退到后台并处于suspend状态, 这时手动kill并不会按照上面方式调用exit, 而是发送SIGKILL signal, 直接终止程序。

4. exit和多线程

当exit被调用时, 如果其它线程正在执行并且访问了 global或者staic c++ object对象时, 则可能由于这些对象已被销毁而出现无法预期的内存错误,比如:SIGBUS,SIGSEGV。 如需避免该问题可以有以下一些处理方案:
1). 把对象从static storage移动heap上, 避免exit过程销毁对象而出现非预期结果
比如:
MyObject gObj("global obj");
// ------>
MyObject* pObj = new MyObject("global obj ptr");
2). 通过atexit注册回调, 或者applicationWillTerminate(iOS) 中结束子线程避免引用可能销毁的对象。
5. iOS上终止程序
1).  主动调用exit或用户终止(程序未进入suspend状态, applicationDidEnterBackground 未回调

在iOS上可以直接调用exit(0)终止程序,也会按照上面说到的cleanup清理c++ object. (注:iOS 7.0模拟器未做清理,iPhone和7.1模拟器都ok, 估计是模拟器bug)
2). 如果程序已经进入suspend状态 applicationDidEnterBackground已经回调,则系统会直接发送SIGKILL强制程序直接结束
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

iOS exit函数深入浅出 的相关文章

随机推荐