簡 述: 前面幾篇,剛寫過了父子進程的實例。這裏寫一個守護進程 的例子,從瞭解到運用 setsid()
;守護進程也就是脫離於終端,不需要和用戶交流的,不受註銷影響的後臺程序(可理解爲 win 中的服務 )。
編程環境:
💻: uos20
📎 gcc/g++ 8.3
📎 gdb8.0
💻: MacOS 10.14
📎 gcc/g++ 9.2
📎 gdb8.3
守護進程的特點:
- 後臺服務程序
- 獨立(是脫離於)控制終端的,用戶不需要和終端交互
- 週期性的執行某任務
- 不受用戶登錄註銷的影響
- 一般採用 d 結尾的名字(服務)
進程組 - 多個進程:
- 進程組的組長?
- 組長是是組裏的第一個進程
- 進程組的 ID == 進程組的組長的 ID
會話 - 多個進程組:
進程組是由多個進程組成,而會話是由多個進程組組成成。
- 創建一個會話注意的事項:
- 不能是組長進程
- 創建會話的進程成爲新進程組的組長
- 有些 Linux 版本需要 root 權限執行此操作(Ubuntu 不需要)
- 創建出的新會話會丟棄原有的控制終端
- 一般步驟:先 fork(),父親死,兒子創建繪畫操作(setsid())
- 獲取進程所屬的會話 ID:
pid_t getsid(pid_t pid);
- 創建一個會話:
pid_t setsid(void);
創建守護進程模型:
下面列出創建一個標準的進程守護模型操作流程:
- fork() 進程,父進程退出 (必須)
- 子進程創建新的會話 (必須)
- 使用
setsid()
- 使用
- 改變當前工作目錄 chdir (可選)
- 比如,U 盤插在筆記本,運行 U 盤文件夾裏面的可執行程序,然後拔掉,會有一些影響
- 重設文件掩碼 (可選)
- 子進程會繼承父進程的掩碼
- 增加子進程程序操作的靈活性
- umask(0)
- 關閉文件描述符 (可選)
- 節約資源,關閉此進程的 PCB 的文件描述符表中 0、1、2 三個,因爲預警不需要和終端交互,故可關閉
- 執行核心工作 (必須)
- 你想讓該守護進程乾的事情
寫一個例子:
對上面的函數使用,寫一個例子:寫一個守護進程,每隔 2s 獲取一次系統時間,寫入到文本文件中。
-
代碼示例
#include <stdio.h> #include <unistd.h> #include <sys/wait.h> #include <sys/time.h> #include <sys/types.h> #include <fcntl.h> #include <signal.h> #include <sys/stat.h> #include <time.h> void func(int no); //用作回調函數,給 signal() 調用 int main(int argc, char *argv[]) { pid_t pid = fork(); if (pid > 0) { _exit(1); //父進程退出 } else if (pid == 0) { setsid(); //子進程創建爲會話 chdir("/Users/muli/Desktop/"); //改變進程的工作目錄 umask(0); //重設置文件掩碼 close(STDIN_FILENO); //關閉和終端的聯繫,文件描述符 close(STDOUT_FILENO); close(STDERR_FILENO); __sigaction_u sigactu; //設置信號捕捉 sigactu.__sa_handler = func; struct sigaction act; act.sa_flags = 0; act.__sigaction_u = sigactu; sigaddset(&act.sa_mask, SIGQUIT); itimerval time; //設置週期性的定時器 time.it_value.tv_sec = 2; time.it_value.tv_usec = 0; time.it_interval.tv_sec = 1; time.it_interval.tv_usec = 0; sigaction(SIGVTALRM, &act, NULL); //捕捉(下面一行發射的)信號,在 fun() 裏面實現 setitimer(ITIMER_VIRTUAL, &time, NULL); //使用定時器,發射信號 while (true); //保持該守護進程不死亡 } return 0; } void func(int no) { time_t currtime; //獲取系統當前時間,傳出參數 time(&currtime); char* ptr = ctime(&currtime); int fd = open("/Users/muli/Desktop/setsid.txt", O_CREAT | O_WRONLY | O_APPEND, 0777); //寫入磁盤文件 write(fd, ptr, sizeof(ptr) + 1); close(fd); }
-
代碼分析:
這裏
sigaction(SIGVTALRM, &act, NULL);
和代碼setitimer(ITIMER_VIRTUAL, &time, NULL);
這一行,成爲互相對應的關係。,使用了週期定時器 setitimer,第一個參數填了三個枚舉之一,但是對應的 sigaction 信號捕捉中,就要填寫對應的參數(見 man 手冊);注意,要先有捕捉函數,後實現信號發射函數,避免出現信號已經發射了,但是捕捉函數還沒有實現或執行。
-
運行效果:
文件掩碼是什麼?
- linux中的 umask 函數主要用於:在創建新文件或目錄時 屏蔽掉新文件或目錄不應有的訪問允許權限。
- 文件的訪問允許權限共有9種,分別是:rwxrwxrwx
- 它們分別代表:用戶讀 用戶寫 用戶執行 組讀 組寫 組執行 其它讀 其它寫 其它執行
- 更多是使用 umask 命令或者 umask() 函數老表示,比如: 777;
下載地址:
歡迎 star 和 fork 這個系列的 linux 學習,附學習由淺入深的目錄。