進程間的關係

  1. 進程組

        進程組是一個或多個進程的集合。每個進程除了有一個進程ID之外,還屬於一個進程組。每個進程組有一個唯一的進程組ID。每一個進程組都可以有一個組長進程。(一般來說,第一個進程爲組長進程)組長進程的標識是,其進程組ID等於其進程的ID。

        只要某個進程中一個進程還存在,則進程組就存在,與其組長進程是否終止無關。

  2. 作業

        Shell分前後臺控制的不是進程而是作業或者進程組。在命令行上運行一個二進制程序,則是開啓了一個作業。一個前臺作業可以由多個進程組成,一個後臺作業也可以由很多進程組成。

    作業控制:Shell可以運行一個前臺作業和任意多個後臺作業

    作業與進程組的區別:如果作業中的某個進程創建了子進程,則子進程不屬於作業而是屬於一個進                     程組。一旦作業運行結束,Shell就把自己提到前臺,若原來的前臺進程還存                     在,它自動變爲後臺進程。

  3. 會話

    會話是一個或多個進程組的集合。一個會話可以有一個控制終端。

    打開一個終端就相當於打開一個會話。

    控制進程:建立與控制終端連接的會話首進程

    一次會話中應該包括:控制進程(會話首進程),一個前臺進程組和任意後臺進程組


4. 守護進程

   守護進程也稱爲精靈進程。是運行在後臺的一種特殊進程。它獨立於控制終端並且週期性地執行某種任務或等待處理某些發生的進程。

   創建守護進程最關鍵的一步是調用setsid函數創建一個新的會話。

   pid_t setsid(void);

   返回值:成功時,返回新創建的會話的id(其實也是當前進程的id)

           出錯返回-1.

   注:在調用這個函數之前,當前進程不允許是進程組的Leader,否則該函數返回-1.

   成功調用該函數的結果爲:

   <1> 創建一個新的會話,當前進程稱爲會話Leader,當前進程的id就是會話的id

   <2> 創建一個新的進程組,當前進程成爲進程組的Leader,當前進程的id就是進程組的id

   <3> 如果當前進程原本有一個控制終端,則它失去這個控制終端,成爲一個沒有控制終端的進程。所謂失去控制終端是指,原來的控制終端仍然是打開的,仍然可以讀寫,但只是一個普通的打開文件而不是控制終端。


   創建守護進程:

  <1> 調用umask將文件模式創建屏蔽字設置爲0

  <2> 調用fork,父進程退出(exit)。

      原因:一般來說,進程組的第一個進程爲進程組長,fork出子進程,父進程退出,保證子進程不             是一個進程組的組長進程。

  <3> 調用setsid創建一個新會話。setsid會導致(1)調用進程成爲新會話的首進程(2)調用進程成       爲一個進程組的組長進程(3)調用進程沒有控制終端

  <4> 將當前工作目錄更改爲根目錄

  <5> 關閉不在需要的文件描述符

  <6> 忽略SIGCHLD信號

wKiom1eeALeCY1zKAAA-hEOcJc0427.png


創建守護進程:

   int daemon(int nochdir,int noclose)

     當 nochdir爲零時,當前目錄變爲根目錄,否則不變;

     當 noclose爲零時,標準輸入、標準輸出和錯誤輸出重導向爲/dev/null,也就是不輸出任何信 息,否則照樣輸出。

    返回值:

    deamon()調用了fork(),如果fork成功,那麼父進程就調用_exit(2)退出,所以看到的錯誤信息 全部是子進程產生的。如果成功函數返回0,否則返回-1並設置errno

 假如運行成功,父進程在daemon函數運行完畢後自殺,以後的休眠和打印全部是子進程來運行。


在看到有些資料上,創建守護進程時,首先fork子進程,讓父進程終止,然後子進程fork出孫子進程,讓孫子進程setsid。爲什麼要fork兩次呢?


分析:首先第二次fork也不是必須的。第二次fork的主要目的是:防止進程再次打開一個終端。因爲打開一個終端是條件是該進程必須爲會話組長,在fork一次,孫子進程id != sid(sid爲子進程的sid)。所以無法打開新的控制終端。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章