深入浅出 C++:与程序终止相关的函数 PART 2 - quick_exit()、_Exit()

quick_exit() 与 at_quick_exit() (C++11新增)

[[noreturn]] void quick_exit(int status) noexcept;

quick_exit() 为 C++11 引入的函数,如果程序有特殊理由,想直接结束、但又不希望呼叫到对象的 destructor 时,就能派上用处。

相对于 exit() 与 atexit(),quick_exit() 亦有 at_quick_exit(),用来注册当 quick_exit() 调用后,还需处理的事情。C++ 标准同样保证 at_quick_exit() 至少能注册 32 个函数,且执行的顺序与注册的顺序相反。

extern "C" int at_quick_exit (void (*func)(void)) noexcept;
extern "C++" int at_quick_exit (void (*func)(void)) noexcept;

at_quick_exit 注册的函数,与 at_exit 注册的是隔离的,两不相干,端看程序是以 exit() 结束、还是 quick_exit() 结束。若 main() 函数正常结束,则是调用 exit()、并触发 at_exit() 注册的函数执行。

#include <iostream>
#include <cstdlib>
#include <thread>

void Print(const std::string&s, int m)
{
  std::cout << s << ", m_ = " << m
            << ", thread_id = " << std::this_thread::get_id() << std::endl;
}

class MyClass
{
public:
  MyClass(int a) : m_(a) { Print("Constructor", m_); }
  ~MyClass()             { Print("Destructor", m_);  }
  void Show()            { Print("Show", m_);        }
private:
  int m_;
};


void ExitFunction1() { std::cout << "ExitFunction1()" << std::endl; }
void ExitFunction2() { std::cout << "ExitFunction2()" << std::endl; }
void ExitFunction3() { std::cout << "ExitFunction3()" << std::endl; }
void ExitFunction4() { std::cout << "ExitFunction4()" << std::endl; }

MyClass c1(1);
thread_local MyClass c2(2);

int main()
{
  std::cout << "Begin of main()" << std::endl;
  static MyClass c3(3);
  MyClass c4(4);
  c2.Show();

  std::atexit(ExitFunction1);
  std::at_quick_exit(ExitFunction2);
  std::at_quick_exit(ExitFunction3);
  std::at_quick_exit(ExitFunction4);

  std::cout << "Call quick_exit()" << std::endl;
  std::quick_exit(EXIT_SUCCESS);

  std::cout << "End of main()" << std::endl;
}
sora@sora-VirtualBox:~/cpp/c2$ clang++ -std=c++17 -stdlib=libc++ --pedantic-errors -pthread -o quick_exit quick_exit.cpp
sora@sora-VirtualBox:~/cpp/c2$ ./quick_exit 
Constructor, m_ = 1, thread_id = 140176298325824
Begin of main()
Constructor, m_ = 3, thread_id = 140176298325824
Constructor, m_ = 4, thread_id = 140176298325824
Constructor, m_ = 2, thread_id = 140176298325824
Show, m_ = 2, thread_id = 140176298325824
Call quick_exit()
ExitFunction4()
ExitFunction3()
ExitFunction2()


_Exit() (C++11 新增)

[[noreturn]] void _Exit (int status) noexcept;

如果不想在程序结束时,调用任何对象的 destructor、也不想执行任何由 atexit()、at_quick_exit() 注册的函数,则可使用 _Exit() 结束。

exit() 结束 process 的过程中,除了调用 atexit() 注册的函数,还会 flush 并 close stdio stream。考虑一种情况,如果一个 parent process fork 出一个 child process,若 child process 使用 exit() 结束,child process 会强制 flush 残留在内存中的 stdio stream,而当 parent process 结束时,他也 flush 了 stdio stream,就会导致 flush 两次重复的结果。下面范例说明这种情况:

#include <iostream>
#include <cstdlib>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

int main()
{
  std::cout << "Hello World";

  pid_t pid = fork();
  if (pid == 0) // child process
  {
    std::exit(0);
  }
  else if (pid > 0)
  {
    int status;
    waitpid(pid, &status, 0);
    std::cout << std::endl << "Child process has exited" << std::endl;
  }
  else
  {
    std::cerr << "fork failed" << std::endl;
  }

}

从下面执行的结果,可看到 Hello World 输出了两次,原因就在于 child process 执行的 exit() 触发了 fluch stdio stream。

sora@sora-VirtualBox:~/cpp/c2$ clang++ -std=c++17 -stdlib=libc++ --pedantic-errors -pthread -o _Exit _Exit.cpp
sora@sora-VirtualBox:~/cpp/c2$ ./_Exit
Hello WorldHello World
Child process has exited

上述问题,只要将第 10 行改为调用 std::_Exit(0),就不会发生。

fork() 的目的,是让 child process 与 parent 具有相同的内存内容、再执行不同的代码,所以 fork 前未摧毁的类、未 flush 的 stdio stream 等,都会带到 child process。这些类的 destructor,可能做了某些复杂的行为、不适合重复执行,而 stdio stream 也不适合 flush 重复的内容,在此情况下,就可考虑用 _Exit() 解决问题。

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C++的algorithm库中的lower_bound函数用于在有序序列中查第一个不小于给定值的元素的位置。它的原型为:iterator lower_bound (const value_type& val) const; [1] lower_bound函数返回的是一个迭代器,指向序列中第一个不小于给定值的元素,如果找不到这样的元素,则返回指向序列末尾的迭代器。 下面是lower_bound函数的使用示例: ```cpp int a = {0, 1, 3, 5, 8, 10, 16}; int* result = lower_bound(a, a + 7, 3); ``` 在上面的示例中,lower_bound函数会返回一个指向序列a中第一个不小于3的元素的指针,即指向数字3的位置。 需要注意的是,lower_bound函数要求序列必须是有序的,否则结果将是不确定的。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* [C++:lower_bound 和 upper_bound](https://blog.csdn.net/weixin_43414130/article/details/104719988)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *2* [使用std::lower_bound和std::upper_bound解决常见的二分查找问题](https://blog.csdn.net/anakin7/article/details/71055747)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] - *3* [lower_bound()/upper_bound()函数(C++)](https://blog.csdn.net/weixin_51566349/article/details/128086465)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v92^chatsearchT3_1"}}] [.reference_item style="max-width: 33.333333333333336%"] [ .reference_list ]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值