Linux: 守護進程
- (一)前臺進程和后臺進程
- 前臺進程
- 后臺進程
- (二)會話、進程組、進程的關系
- (三)守護進程
- 創建守護進程
(一)前臺進程和后臺進程
前臺進程
前臺進程是指當前正在終端中運行,并占用標準輸入、輸出和錯誤輸出的作業。它通常與用戶的交互密切相關,例如用戶正在使用的應用程序或服務。
后臺進程
后臺進程則是指不直接與用戶交互的應用程序或服務。這類進程可能仍然在執行某些任務,但并不占據用戶的注意力。
創建后臺進程:
可執行程序 &
jobs
命令:
jobs 是一個用于查看當前 shell 中后臺作業狀態的內置命令。它主要用于顯示由當前 shell 啟動并仍在運行或已停止的作業列表。
fg + 后臺進程號
命令:
將后臺任務提到前臺
bg + 后臺進程號
:
將已暫停的后臺進程重啟
(二)會話、進程組、進程的關系
實際上我們使用 XShell 等工具登錄 Linux 服務器時,會在服務器中創建一個 會話(bash),可以在該會話內創建 進程,當 進程 間有關系時,構成一個 進程組,組長 進程的 PID 就是該 進程組 的 PGID。
我們通過下面這個例子來驗證上面的結論
sleep 1000 | sleep 2000 | sleep 3000 &sleep 100 | sleep 200 | sleep 300
可以發現 每一組的進程組 PGID 都與當前組中第一個被創建的進程 PID 一致,這個進程被稱為 組長進程。無論是 后臺進程 還是 前臺進程,都是從同一個 bash 中啟動的,所以它們處于同一個 會話 中,SID 和 終端文件 TTY 都是一樣的。
每一個進程組就是執行同一個任務,只不過一個任務被分成了不用進程去執行。
Linux 中一切皆文件,終端文件也是如此,這里的終端其實就是當前 bash 輸出結果時使用的文件(也就是屏幕),終端文件位于 dev/pts 目錄下,如果向指定終端文件中寫入數據,那么對方也可以直接收到
bash 進程本質上就是一個不斷運行中的 前臺進程,并且自成 進程組。
所以 SID 其實就是 bash 的 PID。在同一個 bash 中啟動前臺、后臺進程,它們的 SID 都是一樣的,屬于同一個 會話,關聯了同一個 終端。
(三)守護進程
守護進程:進程單獨成一個會話,并且以后臺進程的形式運行。
應用場景:一種長期運行的后臺任務,通常用于執行諸如日志記錄、定時任務或其他需要持續運行的服務功能。
創建守護進程
方法一:
該函數用于創建守護進程,原型如下:
#include <unistd.h>
int daemon(int nochdir, int noclose);
參數說明:
- nochdir 改變進程的工作路徑
通常,daemon 函數會將當前工作目錄更改為根目錄(“/”),以避免當前目錄被卸載。 - noclose 重定向標準輸入、標準輸出、標準錯誤
返回值:
- 成功返回 0,失敗返回 -1
使用:
程序中調用 daemon(0, 0);
方法二:
通過創造會話手動 創造守護進程,系統提供的接口一鍵 守護進程化 固然方便,不過大多數程序員都會選擇手動 守護進程化(可以根據自己的需求定制操作)
該函數用于創建一個會話。創建會話需要注意不能是一個進程組的組長(即進程組的id不能是該進程的pid)
#include <unistd.h>
pid_t setsid(void);
返回值:
- 成功返回該進程的 pid,失敗返回 -1
手動實現守護進程需注意以下幾點:
- 忽略異常信號
避免異常信號影響守護進程 - 0、1、2 要做特殊處理(文件描述符)
守護進程一般只要保持運行即可,不需要進行輸入輸出(比如服務器),若有需要關注的信息可以寫入日志中。 - 進程的工作路徑可能要改變(從用戶目錄中脫離至根目錄)
改變守護進程的路徑到 一個安全的位置, 避免目錄的變動影響 守護進程
使用例子:
#pragma once #include <fcntl.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <stdlib.h>
#include <string>const std::string nullfile = "/dev/null";void _Daemon(const std::string& cwd = “”)
{// 1.忽略其他信號signal(SIGCLD, SIG_IGN);signal(SIGPIPE, SIG_IGN);signal(SIGSTOP, SIG_IGN);// 2.將自己設置為獨立會話 ---創建會話需要注意不能是一個進程組的組長,通過fork函數來完成。if (fork() > 0) exit(0); // 父進程直接退出setsid();// 3.更改文件的目錄if (!cwd.empty()) chdir(cwd.c_str());// 4.將標準輸入標準輸出標準錯誤重定向到/dev/null這個垃圾桶文件中int fd = open(nullfile.c_str(), O_RDWR);if (fd > 0){// 重定向dup2(fd, 0); dup2(fd, 1);dup2(fd, 2);close(fd);}
}
/dev/dull 就是一個垃圾桶文件。
總的來說 守護進程用于在后臺運行且獨立于控制終端的特殊進程。它通常由系統啟動并持續運行,提供各種服務而不受用戶交互影響。這些進程主要用于執行定期任務、監控系統狀態以及響應網絡請求等功能。