iOS exit函数深入浅出

来源:互联网 发布:男生挂件知乎 编辑:程序博客网 时间:2024/06/03 16:00

1.   exit函数

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

[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. 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如下:

[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. thread_local Object obj;  //Object为C++类  
  2. thread_local int value = 1;  


第二点:
static storage指的是全局或者函数中static方式定义的变量, 该部分变量会存储到静态存储区(区别于heap和stack), 比如:
[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. Object gObj;  
  2.   
  3. void fun(){  
  4.   
  5.   static Object sObj;  
  6.   
  7. }  
atexit设置的函数在exit过程中会被调用, atexit函数定义如下:
[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. int atexit (void (*func)(void));  
atexit例子如下:
[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. /* atexit example */  
  2. #include <stdio.h>      /* puts */  
  3. #include <stdlib.h>     /* atexit */  
  4.   
  5. void fnExit1 (void)  
  6. {  
  7.   puts ("Exit function 1.");  
  8. }  
  9.   
  10. void fnExit2 (void)  
  11. {  
  12.   puts ("Exit function 2.");  
  13. }  
  14.   
  15. int main ()  
  16. {  
  17.   atexit (fnExit1);  
  18.   atexit (fnExit2);  
  19.   puts ("Main function.");  
  20.   exit(0);  
  21. }  
输出为:
[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. Main function.  
  2. Exit function 2.  
  3. Exit function 1.  
对C++ object销毁顺序, 可以看以下例子:
[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. #include <stdio.h>  
  2. #include <stdlib.h>  
  3. #include <unistd.h>  
  4. #include <thread>  
  5. #include <string>  
  6. #include <iostream>  
  7.   
  8. class MyObject  
  9. {  
  10. public:  
  11.     std::string str;  
  12. public:  
  13.     MyObject(std::string str){  
  14.         this->str = str;  
  15.     }  
  16.       
  17.     ~MyObject(){  
  18.         printf("%s -- %s\n", __FUNCTION__, str.c_str());  
  19.     }  
  20. };  
  21.   
  22.   
  23. void thread_fun(int n)  
  24. {  
  25.     thread_local MyObject threadObj("thread_local subthread  obj");  
  26.     //do something  
  27.     sleep(2);  
  28. }  
  29.   
  30. void exit_fun(){  
  31.     MyObject threadObj("atexit obj");  
  32.     //do something  
  33.     sleep(1);  
  34. }  
  35.   
  36. MyObject obj("global obj");  
  37. int main(int argc, const char * argv[])  
  38. {  
  39.     thread_local MyObject threadObj("thread_local mainthread  obj");  
  40.     static MyObject staticObj("fun static obj");  
  41.     std::thread t(thread_fun, 1);  
  42.     atexit(exit_fun);  
  43.       
  44.     sleep(2);  
  45.     exit(0);  
  46. }  
输出:
[cpp] view plaincopy在CODE上查看代码片派生到我的代码片
  1. ~MyObject -- thread_local subthread  obj   
  2. ~MyObject -- thread_local mainthread  obj  
  3. ~MyObject -- atexit obj  
  4. ~MyObject -- fun static obj  
  5. ~MyObject -- global obj  
  6. 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过程销毁对象而出现非预期结果
比如:
[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. MyObject gObj("global obj");  
  2. // ------>  
  3. 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强制程序直接结束

0 0
原创粉丝点击