1. 程式人生 > >深入淺出 C++:與程式終止相關的函式 PART 2

深入淺出 C++:與程式終止相關的函式 PART 2

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; }
[email protected]:~/cpp/c2$ clang++ -std=c++17 -stdlib=libc++ --pedantic-errors -pthread -o quick_exit quick_exit.cpp
[email protected]:~/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。

[email protected]:~/cpp/c2$ clang++ -std=c++17 -stdlib=libc++ --pedantic-errors -pthread -o _Exit _Exit.cpp
[email protected]:~/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() 解決問題。

相關推薦

深入淺出 C++程式終止相關函式 PART 3

Markdown 編輯器真是不好用,這個文章裡,好幾個程式輸出的地方,# 開頭的都被識別成標題了。如果在 # 前面加上 \,看起來似乎能解決,但好幾行一改,又變成能在文章內看到 \ # 開頭了。哎,試了半個小時,懶得再試了,客官們擔待些,反正對理解正文沒影響便是

深入淺出 C++程式終止相關函式 PART 1

C/C++ 程式,一般是藉由 main() 的返回值呼叫 exit() 函式以正常結束程式。除了程式崩潰、或使用者強制結束程式外,C++ 亦提供數個函式,允許呼叫以立即終止程式,本文將一一介紹這些函式。 不過,在進入主題前,需提醒讀者:撰寫程式時,儘可能使程式

深入淺出 C++程式終止相關函式 PART 2

quick_exit() 與 at_quick_exit() (C++11新增) [[noreturn]] void quick_exit(int status) noexcept; quick_exit() 為 C++11 引入的函式,如果程式有特殊理

C#四捨五入程式

問題 C#中的Math.Round()不是"四捨五入"法; 其實在VB、VBScript、C#、J#、T-SQL中Round函式採用的都是 Banker's rounding(銀行家演算法),即:四捨六入五取偶。 這是IEEE的規範; .NET 2.0 開始,Math.

C#修改程式集資訊後DragDrop註冊失敗

因為某些原因,要修改原來的程式集名稱、namespace名稱,修改完後再執行時,在 Application.Run(new fMain()); 執行之後出現了“DragDrop註冊失敗”的錯誤。 百度一下,發現造成這個錯誤的原因各種各樣,只能自己試試了。 關閉程式集,將Re

C語言組合語言之間的函式呼叫

教材:嵌入式系統及應用,羅蕾、李允、陳麗蓉等,電子工業出版社 ARM 程式設計 C與彙編之間的函式呼叫 ATPCS簡介 ARM-Thumb 過程呼叫標準 ATPC

Linux C的檔案操作及相關函式

一、Linux檔案的屬性及檔案的分類 二、檔案描述符的概念及作用 三、系統呼叫的概念 三、不帶快取的檔案I/O操作的相關函式 四、帶快取的檔案I/O操作的相關函式 一、Linux檔案的屬性 檔案的屬性: 我們在Gcc編譯器輸入“ ls  -al"指令時,除了有不同

Linux之父炮轟C++糟糕程式設計師的垃圾語言

眾所期待的程式設計聖經 【寫在前面】此文貼出後,引起了大家的較多關注,是意料之中的事情。畢竟,C、C++、Linux之父,都是大家最最熟悉的東西。但是許多同學把精力放在純粹語言優劣的爭論上,就沒有太大意思了。這場爭論的主角之一,微軟的Dmitry Kakurin有一句話

C語言線性單鏈表相關函式和演算法的基本實現

備考期間嘗試寫了一些基本資料結構的C語言實現,現做以下記錄(基本資料元以int型為例):全域性定義及依賴:#include <stdio.h> #include <stdlib.h> #define OK 1 #define ERROR 0 #d

深入淺出 C++#include Directive PART 1

除了基本語法外,使用 C++ 提供的標準庫、型別定義等,都需要使用 #include 引入 header file,寫法如下: #include <iostream> #include <vector> #include <s

深入淺出 C++main()

main() 是 C/C++ 程式執行的進入點,作業系統執行程式時,首先會執行 Runtime Library 內的函式進行必要的初始化,接著才呼叫 main() 轉移控制權,當 main() 返回時,再根據 main() 的返回值呼叫 exit() 結束程式。

【theano-windows】學習筆記十一——theano中神經網路相關函式

前言 經過softmax和MLP的學習, 我們發現thenao.tensor中除了之前的部落格【theano-windows】學習筆記五——theano中張量部分函式提到的張量的定義和基本運算外, 還有一個方法稱為nnet, 如果自己實現過前面兩篇部落格中的程

Python中列表、元組、字典、集合字串,相關函式,持續更新中……

> 本篇部落格為博主第一次學 Python 所做的筆記(希望讀者能夠少點浮躁,認真閱讀,平心靜氣學習!) **補充:** - 列表、元組和字串共同屬性: - 屬於有序序列,其中的元素有嚴格的先後順序 - 都支援雙向索引,索引範圍 [ -L, L-1 ] ,L -- 表示列表、元組和字串的長度(分正向索引

持續集成持續部署寶典Part 2創建持續集成流水線

假設 文件 如果 運行 刪除 成功 方法 開發模式 system 在本系列文章中,我們將探討在容器時代如何在基於Docker的環境中創建連貫的工作流程和流水線來簡化大規模項目的部署。另外,我們還將詳細介紹如何利用Docker和Rancher自動化處理這些工作流。 在上文《將

【讀書1】【2017】MATLAB深度學習——代價函式比較(2)

如果你覺得很難趕上學習進度,不要氣餒。 If you had a hard time catching on, don’tbe discouraged. 事實上,在研究深度學習時,理解反向傳播演算法並不是一個至關重要的因素。 Actually, understa

c/s應用程式自動更新元件GeneralUpdate3.2.1釋出

一、元件簡介 GeneralUpdate是基於.net standard 開發的一款(c/s應用)自動升級程式。該元件將更新的核心部分抽離出來方便應用於多種專案當中目前適用於wpf,控制檯應用,winfrom。 本元件(除Single元件僅支援Framework以外)均支援框架版本 .NET Framewo

C++ and OO Num. Comp. Sci. Eng. - Part 2.

its ted 增加 數字 gin logs markdown 模板函數 mar 本文參考自《C++ and Object-Oriented Numeric Computing for Scientists and Engineers》。 1. Basic Types 在

Python學習筆記 Day8 函式 part 2

Day 8 函式 part 2 函式 列表作為引數 傳遞列表的副本 利用切片:sample_list[:] 傳遞任意數量的實參 預先不知道函式接受多少個實參

【MOOC】Python網路爬蟲資訊提取-北京理工大學-part 2

【第二週】 網路爬蟲之提取 Beautiful Soup庫入門 Beautiful Soup庫的安裝與測試 <html><head><title>This is a python demo page<

the c programming language second edition 第四章函式程式結構筆記及練習題中

the c programming language second edition 第四章函式與程式結構筆記 4.3外部變數 C語言程式可以看成由一系列的外部物件構成,這些外部物件可能是變數或函式 外部變數和函式具有以下性質:通過同一個名字對外部變數的所有引