27.1 進程組
27.1.1 進程組介紹
- 進程組為一個或多個進程的集合
- 進程組可以接受同一終端的各種信號,同一個信號發送進程組等於發送給組中的所有進程
- 每個進程組有唯一的進程組 ID
- 進程組的消亡要等到組中所有的進程結束
- 進程組的消亡:kill 發送信號給進程組
- kill -9 -進程組號
27.1.2 進程組 ID 獲取--- getpgrp 和 getpgid
(1)getpgrp --- 獲取調用進程的進程組ID
1 #include <unistd.h> 2 pid_t getpgrp(void);
- 函數說明
- getpgrp()用來取得目前進程所屬的組識別碼。此函數相當於調用 getpgid(0);
- 返回值
- 返回目前進程所屬的組識別碼。
(2)getpgid --- 獲取 pid 所在進程組的 ID
1 #include <unistd.h> 2 pid_t getpgid( pid_t pid);
- 函數說明
- getpgid()用來取得參數 pid 指定進程所屬的組識別碼。如果參數 pid 為0,則會取得目前進程的組識別碼。
- 返回值
- 執行成功則返回組識別碼,如果有錯誤則返回 -1 ,錯誤原因存於 errno 中。
- 錯誤代碼
- ESRCH 找不到符合參數 pid 指定的進程。
- getpgid(getpid()) 獲取指定進程的進程組
- getpgid(0) 獲取當前進程的進程組
27.2 組長進程
27.2.1 概念
- 每個進程組可以有個組長進程,組長進程的ID就是進程組的ID
- 組長進程可以創建進程組以及該組中的進程
- 進程組的創建從第一個進程(組長進程)加入開始
- 進程組的組號取第一個加入組的進程(組長進程)編號
27.2.2 設置進程組 ID--- setpgid(創建進程組或將指定進程加入到指定的進程組中)
1 #include <unistd.h> 2 int setpgid(pid_t pid,pid_t pgid);
- 函數說明
- setpgid() 將參數 pid 指定進程所屬的組 ID 設為參數 pgid 指定的組 ID。如果參數 pid 為 0 ,則會用來設置目前進程的組識別碼,如果參數 pgid 為0,則會以目前進程的進程 ID 來取代。
- 函數功能:將進程加入到指定的進程組中, pid 為進程號, pgid 為組號
- 返回值
- 執行成功則返回組 ID,如果有錯誤則返回-1,錯誤原因存於 errno 中。
- 錯誤代碼
- EINVAL 參數 pgid 小於0。
- EPERM 進程權限不足,無法完成調用。
- ESRCH 找不到符合參數 pid 指定的進程。
27.3 例子
27.3.1 構建進程扇組
構建一個進程扇,要求每兩個進程為一個進程組,如下所示
1 #include <unistd.h> 2 #include <fcntl.h> 3 #include <stdio.h> 4 #include <stdlib.h> 5 #include <sys/wait.h> 6 7 int main(void) 8 { 9 10 //創建進程組,組長進程為父進程 11 setpgid(getpid(), getpid()); 12 13 /* 組1 */ 14 // 或 pid_t group1 = getpgid(0); 15 pid_t group1 = getpgid(getpid()); 16 pid_t group2; 17 18 int i = 0; 19 pid_t pid; 20 21 for(; i < 3; i++) { 22 pid = fork(); 23 if(pid < 0) { 24 perror("fork error`"); 25 exit(1); 26 } else if(pid > 0) {//父進程 27 //父進程中執行和子進程相同的操作 28 if(i == 0) { 29 //要注意fork 在父進程中返回的是子進程的 pid 30 setpgid(pid, group1); 31 } 32 33 //第二個子進程作為組長進程,要創建進程組 34 if(i == 1) { 35 setpgid(pid, pid); 36 group2 = getpgid(pid); 37 } 38 39 if(i == 2) { 40 //第三個子進程加入到 group2 41 setpgid(pid, group2); 42 } 43 } else {//子進程 44 //將第一個子進程加入到 group1 45 if(i == 0) { 46 setpgid(getpid(), group1); 47 } 48 49 //第二個子進程作為組長進程,要創建進程組 50 if(i == 1){ 51 setpgid(getpid(), getpid()); 52 group2 = getpgid(getpid()); 53 } 54 55 if(i == 2) { 56 setpgid(getpid(), group2); 57 } 58 59 //因為是進程扇,每一個子進程要退出循環 60 //父進程繼續循環 fork 61 break; 62 } 63 } 64 65 printf("pid: %d, ppid: %d, pgid: %d\n", getpid(), getppid(), getpgid(0)); 66 67 //防止僵屍進程產生 68 for(i = 0; i < 3; i++) { 69 wait(0); 70 } 71 72 exit(0); 73 }
編譯運行:
27.3.2 構建進程鏈組
1 #include <unistd.h> 2 #include <fcntl.h> 3 #include <stdio.h> 4 #include <stdlib.h> 5 #include <sys/wait.h> 6 7 int main() 8 { 9 //創建進程組1,父進程為組長進程 10 setpgid(getpid(), getpid()); 11 pid_t group1 = getpgid(getpid()); 12 13 pid_t pid; 14 int i = 0; 15 for(;i < 2; i++) { 16 pid = fork(); 17 if(pid < 0) { 18 perror("fork error"); 19 exit(1); 20 } else if(pid > 0) { 21 if(i == 0) { 22 //創建進程組2,第一個子進程作為組長進程 23 setpgid(pid, pid); 24 } 25 26 if(i == 1) { 27 //將第二個子進程加入到 group1中 28 setpgid(pid, group1); 29 } 30 31 // 在進程鏈中,父進程操作完退出循環 32 break; 33 } else if(pid == 0) { 34 35 if(i == 0) { 36 //創建進程組2,第一個子進程作為組長進程 37 setpgid(getpid(), getpid()); 38 } 39 40 if(i == 1) { 41 //將第二個子進程加入到 group1中 42 setpgid(getpid(), group1); 43 } 44 } 45 } 46 47 printf("pid: %d, ppid: %d, pgid: %d\n", getpid(), getppid(), getpgid(0)); 48 49 //防止僵屍進程產生 50 for(i = 0; i < 2; i++) { 51 wait(0); 52 } 53 54 return 0; 55 }
編譯運行:
27.3.3 進程組刪除
1 #include <unistd.h> 2 #include <fcntl.h> 3 #include <stdio.h> 4 #include <stdlib.h> 5 #include <sys/wait.h> 6 7 int main(void) 8 { 9 //創建進程組,父進程作為組長進程 10 setpgid(getpid(), getpid()); 11 12 pid_t pid = fork(); 13 if(pid < 0){ 14 perror("fork error"); 15 exit(1); 16 } else if(pid > 0) { 17 //將子進程加入到父進程所在的組 18 setpgid(pid, getpgid(getpid())); 19 } else { 20 //將子進程加入到父進程所在的組 21 setpgid(getpid(), getpgid(getppid())); 22 } 23 24 printf("pid: %d, ppid: %d, pgid: %d\n", getpid(), getppid(), getpgid(0)); 25 26 pause();//進程暫停,等待信號 27 28 return 0; 29 }
編譯運行:
(1)殺掉進程組
(2)殺掉父進程
殺掉父進程后,子進程依然存在,只不過變成了孤兒進程,並被2323進程所領養
(3)殺掉子進程
子進程變為了僵屍進程,子進程被殺死,但是父進程並沒有回收子進程。
殺掉父進程:
僵屍進程被回收
27.3.4 子進程不加入父進程組中
1 #include <unistd.h> 2 #include <fcntl.h> 3 #include <stdio.h> 4 #include <stdlib.h> 5 #include <sys/wait.h> 6 7 int main(void) 8 { 9 //創建進程組,父進程作為組長進程 10 setpgid(getpid(), getpid()); 11 12 pid_t pid = fork(); 13 if(pid < 0){ 14 perror("fork error"); 15 exit(1); 16 } else if(pid > 0) { 17 //將子進程加入到父進程所在的組 18 setpgid(pid, getpgid(getpid())); 19 } else { 20 //將子進程加入到父進程所在的組 21 //setpgid(getpid(), getpgid(getppid())); 22 } 23 24 printf("pid: %d, ppid: %d, pgid: %d\n", getpid(), getppid(), getpgid(0)); 25 26 pause();//進程暫停,等待信號 27 28 return 0; 29 }
編譯運行:
沒有將子進程加入到組中,依然將子進程加入到父進程組了。
注意:從 shell 上啟動一個父進程,然后從父進程上創建若干個子進程,默認情況下都加入到父進程所在的組中,組號就是父進程的 PID,組長就為父進程。