第7章 进程关系(3)_进程组和组长进程
3. 进程组和组长进程
(1)进程组
①一个或多个进程的集合;
②可以接受同一终端的各种信号,同一个信号发送进程组就等于发送给组中的所有进程。
③每个进程组有唯一的进程组ID
④进程组的消亡要等到组中所有的进程结束;
⑤kill发送信号组进程组:kill -9 -进程组号(注意进程组号前的“-”)
(2)组长进程
①每个进程组可以有个组长进程,组长进程的ID就是进程组的ID。
②组长进程可以创建进程组及该组中的进程。
③进程组的创建从第一个进程(组长进程)加入开始。
④进程组的组号取第一个加入组的进程(组长进程)的编号
(3)获取或设置进程组ID
|
头文件 |
#include <unistd.h> |
|
函数 |
pid_t getpgrp(void); //返回调用进程的进程组ID pid_t getpgid(pid_t pid); //进程pid所在进程组的ID,出错返回-1 int setpgid(pid_t pid, pid_t pgid); //将进程加入到指定的进程组中,其中pid为进程号,pgid为进程组号。成功返回0,出错返回-1。 |
|
功能 |
获取或设置进程组ID |
|
备注 |
①getpgid(0)与getpgid(getpid())等价,都是获得当前进程的进程组ID ②第1次调用setpgid,则创建一个进程组,而调用进程成为组长进程。如 setpgid(getpid(), getpid());//第2个参数为进程组ID,也是组长进程。 ③②用fork创建一个新进程后,子进程默认是和父进程在一个进程组内。 |
【编程实验】1.进程扇与分组

//process_swing_group.c
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char* argv[])
{
pid_t pid;
int i = 0;
//创建进程组,组长进程为父进程
setpgid(getpid(), getpid());
pid_t group1 = getpgid(getpid()); //获取进程组ID
pid_t group2;
//构建进程扇
for(i = 0; i<3; i++) {
pid = fork();
if(pid < 0 ){
perror("fork error");
exit(1);
}else if(pid > 0) { //parent process
//父进程中执行和子进程相同的操作,因为父、子进程
//谁先被调用未知,所以设置进程组ID时,需要父子进程同时设置
//以确保不管谁先运行,都能正确将他们分组
if(i == 0){
//将第一个子进程加入到group1中
setpgid(pid, group1);
}
if(i == 1){
//创建进程组,第二个子进程为组长进程
setpgid(pid, pid);
group2 = getpgid(pid);
}
if(i == 2){
//第3个子进程加入到group2中
setpgid(pid, group2);
}
continue; //父进程继续运行,创建新的子进程
}else{
if(i == 0){
//将第一个子进程加入到group1中
setpgid(getpid(), group1);
}
if(i == 1){
//创建进程组,第二个子进程为组长进程
setpgid(getpid(), getpid());
group2 = getpgid(getpid());
}
if(i == 2){
//第3个子进程加入到group2中
setpgid(getpid(), group2);
}
break; //要构建进扇,子进程须退出。
}
}
printf("pid = %d, ppid = %d, pgid = %d\n",
getpid(), getppid(), getpgid(0));
for(i=0; i<3; i++)
wait(0);
}
/*输出结果:
pid = 3196, ppid = 2447, pgid = 3196
pid = 3198, ppid = 3196, pgid = 3198
pid = 3197, ppid = 3196, pgid = 3196
pid = 3199, ppid = 3196, pgid = 3198
*/
【编程实验】2.进程链与分组

//process_link_group.c
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char* argv[])
{
setpgid(getpid(), getpid());
pid_t group1 = getpgid(getpid());
pid_t pid;
int i = 0;
//构建进程链
for(i = 0; i<2; i++) {
pid = fork();
if(pid < 0 ){
perror("fork error");
exit(1);
}else if(pid > 0) { //parent process
if(i == 0){
//创建进程组2,第1个子进程作为组长进程
setpgid(pid, pid);
}
if(i == 1){
//将第2个子进程加入到group1
setpgid(pid, group1);
}
break;//在进程链,父进程操作完退出循环
}else{ //child process
if(i == 0){
//创建进程组2,第1个子进程作为组长进程
setpgid(getpid(), getpid());
}
if(i == 1){
//将第2个子进程加入到group1
setpgid(getpid(), group1);
}
continue; //子进程继续创建新的子进程
}
}
printf("pid = %d, ppid = %d, pgid = %d\n",
getpid(), getppid(), getpgid(0));
wait(0);
}
/*
pid = 3216, ppid = 2447, pgid = 3216
pid = 3217, ppid = 3216, pgid = 3217
pid = 3218, ppid = 3217, pgid = 3216
*/
【编程实验】3. 操作进程组
//process_group3.c
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
/*父子进程加入同一进程组*/
//说明:
//(1)默认即使以下代码中不加入setpgid的操作,fork出来的子进程与父进程仍会默认地属一进程组
//(2)kill -9 -进程组ID,则父子进程均会收到退出进程的信号
//(3)如果先kill父进程,则子进程成为孤儿进程,会被1号进程领养
//(4)如果先kill子进程,则子进程成为僵尸进程。如果再kill父进程,则回收僵尸进程。
int main(void)
{
//创建进程组,父进程作为组长进程
pid_t pid = fork();
if(pid < 0){
perror("fork error");
exit(1);
}else if(pid > 0){ //parent process
//将子进程加入到父进程所在的组
setpgid(pid, getpgid(getpid()));
}else{ //child process
//将子进程加入到父进程所在的组
setpgid(getpid(), getpgid(getppid()));
}
printf("pid = %d, ppid = %d, pgid = %d\n",
getpid(), getppid(), getpgid(0));
pause();//暂停。父子进程都会执行到这里。
return 0;
}
/*输出结果:
pid = 3301, ppid = 2447, pgid = 3301
pid = 3302, ppid = 3301, pgid = 3301
*/

浙公网安备 33010602011771号