APUE3e
簡介
APUE - 全稱 Advanced Programming in the UNIX Environment(Unix 環境高級編程),是 Unix 系統編程領域的必讀經典之一
相較于其他偏理論的操作系統相關書籍,本書從 Unix 操作系統的整體架構出發,以 Unix 系統應用程序開發者的視角,描述了 Unix 操作系統的作用以及它所提供的主要功能,同時作者以深厚的學識和豐富的經驗將本書的知識點融會貫通,最終構成了一張非常龐大的 Unix 系統編程知識脈絡,而非僅僅只是系統調用函數和庫函數的簡單羅列。因此本書的實踐性較強,不僅提供了豐富的案例幫助讀者親自動手實踐相關系統調用函數和庫函數的功能,也在相應案例的背后深入剖析了相關系統調用函數的起源和發展
知識結構
代碼倉庫
https://github.com/silenaker/apue
該倉庫重新整理了書中示例小程序和練習題(與書中并不完全一致),同時參考 man 命令,補充了一些其他書中沒有的示例,拆分了貫穿全書的 apue 庫,使其更好理解,倉庫中的所有示例均已在 macOS Catalina 上全部編譯運行通過
DevOps
調試
子進程調試
子進程調試主要是指在 fork 之后 exec 之前的代碼調試,其他代碼可通過調試器(lldb/gdb)啟動獨立進程進行調試,父進程在調用 fork 后,由于競態條件的影響(參考 Chapter 8 - Process Control/Race Conditions 章節),調試子進程可能會遇到一些麻煩,下面以調試 daemonize 函數為例來說明如何才能正確調試子進程
在編譯 daemon.c (chapters/ch13/daemon.c) 主程序后,我們先直接運行一下,然后通過 ps 命令查看程序的運行情況,發現沒有啟動成功,由于這個程序是以守護進程的方式運行的,它的日志被輸出到了 syslog 系統日志組件,在 Mac 平臺,我們可以通過 Mac 的控制臺應用來查看系統日志,在左側的 system.log 欄目里面,我們發現了 daemon 程序的輸出結果
通過這個結果我們可以知道進程終止和系統調用失敗的原因,但我們并不知道具體在程序的哪一行代碼發生了問題,因此這個時候我們就需要利用調試器(lldb/gdb)來對我們的代碼進行 line-by-line 的精準調試
首先我們啟動 lldb,載入需要調試的程序(編譯時已設置調試選項),因為我們需要對子進程進行調試,所以我們在 fork 系統調用函數這里設置一個斷點,然后啟動程序,如下圖
此時子進程還沒有啟動,由于我們不能在同一個 lldb 會話中同時調試多個進程(process detach 命令會使進程忽略調試信號,正常運行),因此我們還需要啟動另一個 lldb 會話并加載同一個程序,然后執行 process attach -w 等待子進程的創建,由于父子進程的競態條件,attach 命令可能會以失敗告終(lldb 檢測到新的進程后馬上就嘗試 attach,但此時子進程還沒有從 fork 系統調用中返回,因此 attach 失敗)
與此同時,父進程已經從 fork 中返回了,如果此時繼續調試父進程或執行 process detach 使父進程正常運行直至終止,子進程可能永遠也得不到執行機會,而在父進程終止時,由于父子進程同屬于以父進程為首的進程組,該進程組自然就變成了孤兒進程組,那么子進程也會被 init 進程所發送的 SIGHUP 信號所終止,因此在這種情況下,我們是沒辦法調試子進程的
那么,有什么解決辦法嗎
這個問題的本質是由于父子進程的競態條件,子進程無法得到執行機會,所以只要我們想辦法在 fork 后讓系統調度運行子進程,并在子進程內預留一些操作時機,比如通過 pause() 或 sleep(10) 阻塞子進程,使我們能夠在子進程退出前 attach,那么這個問題就迎刃而解了,需要注意的是我們同時也要保證在調試完成之前父進程不能被終止,否則子進程也會被終止,除非我們在子進程中主動忽略 SIGHUP 信號
總結
- 上一篇: python下载bt文件_使用libto
- 下一篇: Java实现OPC UA Client直