potplayer 多个进程_创建守护进程的步骤
什么是守護進程?
答:守護進程是后臺運行的、系統啟動是就存在的、不予任何終端關聯的,用于處理一些系統級別任務的特殊進程。
實現思路:
實現一個守護進程,其實就是將普通進程按照上述特性改造為守護進程的過程。
需要注意的一點是,不同版本的 Unix 系統其實現機制不同,BSD 和 Linux 下的實現細節就不同。
根據上述的特性,我們便可以創建一個簡單的守護進程,這里以 Linux 系統下從終端 Shell 來啟動為例。
在此有必要說一下兩個概念:會話和進程組。
參考 https://www.cnblogs.com/zengyiwen/p/5755191.html
進程都有父進程,父進程也有父進程,這就形成了一個以init進程為根的家族樹。除此以外,進程還有其他層次關系:進程、進程組和會話。進程組和會話在進程之間形成了兩級的層次:進程組是一組相關進程的集合,會話是一組相關進程組的集合。
這樣說來,一個進程會有如下ID:
·PID:進程的唯一標識。對于多線程的進程而言,所有線程調用getpid函數會返回相同的值。
·PGID:進程組ID。每個進程都會有進程組ID,表示該進程所屬的進程組。默認情況下新創建的進程會繼承父進程的進程組ID。
·SID:會話ID。每個進程也都有會話ID。默認情況下,新創建的進程會繼承父進程的會話ID。
前面提到過,新進程默認繼承父進程的進程組ID和會話ID,如果都是默認情況的話,那么追根溯源可知,所有的進程應該有共同的進程組ID和會話ID。但是調用ps axjf可以看到,實際情況并非如此,系統中存在很多不同的會話,每個會話下也有不同的進程組。
為何會如此呢?
就像家族企業一樣,如果從創業之初,所有家族成員都墨守成規,循規蹈矩,默認情況下,就只會有一個公司、一個部門。但是也有些“叛逆”的子弟,愿意為家族公司開疆拓土,愿意成立新的部門。這些新的部門就是新創建的進程組。如果有子弟“離經叛道”,甚至不愿意呆在家族公司里,他別開天地,另創了一個公司,那這個新公司就是新創建的會話組。由此可見,系統必須要有改變和設置進程組ID和會話ID的函數接口,否則,系統中只會存在一個會話、一個進程組。
進程組和會話是為了支持shell作業控制而引入的概念。
當有新的用戶登錄Linux時,登錄進程會為這個用戶創建一個會話。用戶的登錄shell就是會話的首進程。會話的首進程ID會作為整個會話的ID。會話是一個或多個進程組的集合,囊括了登錄用戶的所有活動。在登錄shell時,用戶可能會使用管道,讓多個進程互相配合完成一項工作,這一組進程屬于同一個進程組。
當用戶通過SSH客戶端工具(putty、xshell等)連入Linux時,與上述登錄的情景是類似的。
通常,會話開始于用戶登錄,終止于用戶退出,期間的所有進程都屬于這個會話。一個會話一般包含一個會話首進程、一個前臺進程組和一個后臺進程組,控制終端可有可無;此外,前臺進程組只有一個,后臺進程組可以有多個,這些進程組共享一個控制終端。
- 前臺進程組:
該進程組中的進程可以向終端設備進行讀、寫操作(屬于該組的進程可以從終端獲得輸入)。該進程組的 ID 等于控制終端進程組 ID,通常據此來判斷前臺進程組。 - 后臺進程組:
會話中除了會話首進程和前臺進程組以外的所有進程,都屬于后臺進程組。該進程組中的進程只能向終端設備進行寫操作。
下圖為會話、進程組、進程和控制終端之間的關系(登錄 shell 進程本身屬于一個單獨的進程組)。
想了解更多關于會話 Sessions 內容,可以認真讀一下 APUE 這本書。
如果調用進程非組長進程,那么就能創建一個新會話:
- 該進程變成新會話的首進程
- 該進程成為一個新進程組的組長進程
- 該進程沒有控制終端,如果之前有,則會被中斷(會話過程對控制終端的獨占性)
也就是說:組長進程不能成為新會話首進程,新會話首進程必定成為組長進程。
1、fork()創建子進程,父進程exit()退出;
這是創建守護進程的第一步。由于守護進程是脫離控制終端的,完成這一步后就會在Shell終端里造成程序已經運行完畢的假象。之后的所有工作都在子進程中完成,而用戶在Shell終端里則可以執行其他命令,從而在形式上做到了與控制終端的脫離,在后臺工作。
由于父進程先于子進程退出,子進程就變為孤兒進程,并由 init 進程作為其父進程收養。
2、在子進程調用setsid()創建新會話;
在調用了 fork() 函數后,子進程全盤拷貝了父進程的會話期、進程組、控制終端等,雖然父進程退出了,但會話期、進程組、控制終端等并沒有改變。這還不是真正意義上的獨立開來,而 setsid() 函數能夠使進程完全獨立出來。
setsid()創建一個新會話,調用進程擔任新會話的首進程,其作用有:
- 使當前進程脫離原會話的控制
- 使當前進程脫離原進程組的控制
- 使當前進程脫離原控制終端的控制
這樣,當前進程才能實現真正意義上完全獨立出來,擺脫其他進程的控制。
3、再次 fork() 一個子進程,父進程exit退出;
現在,進程已經成為無終端的會話組長,但它可以重新申請打開一個控制終端,可以通過 fork() 一個子進程,該子進程不是會話首進程,該進程將不能重新打開控制終端。退出父進程。
也就是說通過再次創建子進程結束當前進程,使進程不再是會話首進程來禁止進程重新打開控制終端。
4、在子進程中調用chdir()讓根目錄“/”成為子進程的工作目錄;
這一步也是必要的步驟。使用fork創建的子進程繼承了父進程的當前工作目錄。由于在進程運行中,當前目錄所在的文件系統(如“/mnt/usb”)是不能卸載的,這對以后的使用會造成諸多的麻煩(比如系統由于某種原因要進入單用戶模式)。因此,通常的做法是讓"/"作為守護進程的當前工作目錄,這樣就可以避免上述的問題,當然,如有特殊需要,也可以把當前工作目錄換成其他的路徑,如/tmp。改變工作目錄的常見函數是chdir。(避免原父進程當前目錄帶來的一些麻煩)
5、在子進程中調用umask()重設文件權限掩碼為0;
文件權限掩碼是指屏蔽掉文件權限中的對應位。比如,有個文件權限掩碼是050,它就屏蔽了文件組擁有者的可讀與可執行權限(就是說可讀可執行權限均變為7)。由于使用fork函數新建的子進程繼承了父進程的文件權限掩碼,這就給該子進程使用文件帶來了諸多的麻煩。因此把文件權限掩碼重設為0即清除掩碼(權限為777),這樣可以大大增強該守護進程的靈活性。通常的使用方法為umask(0)。(相當于把權限開發)
6、在子進程中close()不需要的文件描述符;
同文件權限碼一樣,用fork函數新建的子進程會從父進程那里繼承一些已經打開了的文件。這些被打開的文件可能永遠不會被守護進程讀寫,但它們一樣消耗系統資源,而且可能導致所在的文件系統無法卸下。其實在上面的第二步之后,守護進程已經與所屬的控制終端失去了聯系。因此從終端輸入的字符不可能達到守護進程,守護進程中用常規方法(如printf)輸出的字符也不可能在終端上顯示出來。所以,文件描述符為0、1和2 的3個文件(常說的輸入、輸出和報錯)已經失去了存在的價值,也應被關閉。(關閉失去價值的輸入、輸出、報錯等對應的文件描述符)
7、守護進程退出處理
當用戶需要外部停止守護進程運行時,往往會使用 kill 命令停止該守護進程。所以,守護進程中需要編碼來實現 kill 發出的signal信號處理,達到進程的正常退出。
一張簡單的圖可以完美詮釋之前幾個步驟:
至此為止,一個簡單的守護進程就建立起來了。
注意守護進程一般需要在 root 權限下運行。
創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
以上是生活随笔為你收集整理的potplayer 多个进程_创建守护进程的步骤的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 网速dns怎么调快_怎么设置dns?教你
- 下一篇: hp服务器硬盘ultra320,惠普/h