C 語言程式結束時,呼叫 exit() 還是 _exit()?兩者最終都會終止進程,但清理工作截然不同。搞錯可能導致資料遺失(緩衝區未刷新)、資源洩漏(鎖未釋放)、或僵屍進程處理異常。本文從原始碼、POSIX 標準、實際行為三個維度徹底釐清差異。
| 函數 | 標頭檔 | 屬性 |
|---|---|---|
void exit(int status) | <stdlib.h> | C 標準庫函數,非直接系統調用 |
void _exit(int status) | <unistd.h> | POSIX 系統調用封裝(Linux 內核 sys_exit/sys_exit_group) |
exit(status) 等價於:
1. 呼叫所有經 atexit()/on_exit() 登記的「出口函數」(逆序執行)
2. 刷新所有 stdio 緩衝區(fflush(NULL)),關閉所有開啟的串流
3. 刪除 tmpfile() 建立的臨時檔案
4. 呼叫 _exit(status) 進入內核真正終止進程
_exit() 直接進入內核,不執行上述任何用戶空間清理。
SIGCHLD 信號共同點:無論呼叫哪個,內核最終都會回收記憶體、釋放鎖、關閉檔案描述符(步驟 1)。差異在於用戶空間緩衝區與註冊清理函數是否執行。
| 場景 | exit() | _exit() | 後果 |
|---|---|---|---|
printf("data") 後直接結束,無 \n、無 fflush | 緩衝區刷新,資料寫入終端/檔案 | 緩衝區未刷新,資料丟失 | 日志不全、檔案截斷 |
註冊 atexit(save_config) | 程式結束前自動存檔 | 不執行,設定遺失 | 配置未持久化 |
| 持有資料庫鎖、共享記憶體鎖 | 可在 atexit 中釋放 | 鎖永遠不釋放 | 其他進程永久阻塞 |
fork() 子進程中報錯退出 | 執行父進程的 atexit(錯誤!) | 不執行 atexit(正確) | 子進程必須用 _exit() |
| 多執行緒程式主執行緒 return | 相當於 exit(),執行清理 | 不執行清理 | 建議主執行緒用 pthread_exit() 或 return |
pid_t pid = fork();
if (pid == 0) {
// 子進程
if (execve(...) == -1) {
perror("execve");
_exit(EXIT_FAILURE); // 絕不可用 exit()!
}
}
// 父進程繼續...
原因:子進程繼承父進程的 stdio 緩衝區與 atexit 清單。若用 exit(),會雙重刷新緩衝區(資料重複/亂序)、雙重執行清理函數(釋放同一把鎖兩次 → 崩潰)。
/* stdlib/exit.c 簡化版 */
void exit(int status) {
__run_exit_handlers(status, &__exit_funcs, true, true);
}
/* sysdeps/unix/sysv/linux/_exit.c */
void _exit(int status) {
INLINE_SYSCALL(exit_group, 1, status); // 直接系統調用
}
內核入口同樣是 exit_group(現代 Linux 以線程組為單位終止),差異純在用戶空間封裝層。
| Windows API | 對應 Linux | 行為 |
|---|---|---|
ExitProcess | exit() | 執行 DLL_PROCESS_DETACH、CRT 終止、刷新緩衝區 |
TerminateProcess | _exit() | 直接終止,無任何用戶模式清理 |
exit(status) 或直接 return status(main 中)。fork() 子進程 exec 失敗 → _exit(status)。_exit(status)。_exit(),父進程正常 exit()。記住:exit() 是「體面離場」(清理完再走),_exit() 是「拍拍屁股走人」。選對地方用對函數,才能避免資料遺失與資源洩漏的隱形坑。
Linux 查看當前 Shell 的 7 種方法:$SHELL、$0、ps、/etc/passwd、echo $$ 等
Linux 管道機制深度解析:pipe() 系統呼叫、無名/命名管道與實戰範例
CentOS 5.5 安装配置 Puppet 2.6 集中化配置管理:Master/Agent 部署全记录
Linux iptables 防火牆配置實戰:從入門到安全強化
Linux xhost 命令详解:X Server 访问控制与远程图形应用授权
Linux SSH 連線逾時自動斷開?教你輕鬆設定保持長連線
Ubuntu 14.04/14.10 睡眠喚醒後滑鼠鍵盤失靈解決方案:重裝 xserver-xorg-input-all