行程與行程控制

常駐程式(daemon)

/ DEE-mun or DAY-mun /

有些程式是拿來用完就結束的——你執行 ls,它印出來、結束。但另一些則是要在背景安靜地永遠執行,隨時待命去做它的工作:一個等待請求的網頁伺服器、一個等待文件的列印排程器、一個滴答運轉的時鐘同步服務。像這樣以長壽背景行程執行、且沒有控制終端機的程式,就叫常駐程式(daemon)。這個名字(取自一個樂於助人的精靈的古老拼法,不是惡魔)很傳神:一個在背景工作、看不見的幫手。

具體來說,讓一個行程成為常駐程式的,是它刻意把自己與任何終端機、任何使用者工作階段脫離,好讓它不論誰登入都繼續執行。傳統的作法走過幾個步驟:fork() 並讓父行程結束(這樣子行程就不再是行程群組領導者,並成為被 init 收養的孤兒);呼叫 setsid() 開啟一個新工作階段、卸下控制終端機;常常再 fork() 第二次,好讓常駐程式永遠無法重新取得終端機;把工作目錄切到像 / 這樣安全的地方;重設檔案模式遮罩;並關閉或重導向標準輸入、輸出與錯誤串流(通常導到 /dev/null 或日誌檔),因為沒有終端機可讀可寫。結果是一個 PPID 為 1、沒有終端機、能在你登出後存活的行程。在現代系統上你很少需要手工寫這一切——像 systemd 這樣的 init 系統會替你啟動並監督服務,處理脫離、日誌與當掉重啟——但底層的概念是一樣的。

為何重要:常駐程式是電腦提供服務的方式——伺服器「做」的幾乎一切,都是一個耐心等待並回應的常駐程式。理解常駐化把這整個欄位串了起來:它用到 fork(建立行程)、孤兒與重新指派父行程的機制(好讓 init 收養它)、工作階段與控制終端機(用來脫離)、以及憑證(常駐程式通常為安全而降權到非特權使用者)。初學者常犯的錯,是直接從 shell 啟動一個伺服器,然後在關掉終端機把它殺掉時感到意外——那正是真正的常駐程式會謹慎切斷的那條控制終端機連結。

sshd、cron 與像 nginx 這樣的網頁伺服器都是常駐程式:ps 顯示它們的 PPID 為 1、TTY 欄是「?」,表示沒有控制終端機。它們在開機時啟動、脫離了任何工作階段,並在使用者來來去去登入登出時持續執行。

常駐程式:PPID 為 1、沒有控制終端機(TTY 為「?」)、在背景安靜執行。

從 shell 啟動一個伺服器並不會讓它成為常駐程式——它仍繫於那個終端機,並在終端機關閉時死去(一個掛斷信號)。真正的常駐化是刻意透過 setsid 與重新指派父行程脫離;現代系統把這件事交給 systemd 之類處理。

又称
background serviceservice process背景服務守護行程