1. 进程组
(1)概念:一个或多个进程的集合,也称为“作业”。
(2)父进程创建子进程时,默认属于同一个进程组。进程组ID为组长进程ID。
(3)进程组中只要有一个进程存在,进程组就存在,与组长进程是否终止无关。
(4)父子进程可不属于同一进程组。
进程组相关函数
(1)getpgrp函数
#include<unistd.h>
pid_t getpgrp(void);
/*
功能:
获取当前进程的进程组ID
返回值:
总是成功。
*/
(2)getpgid函数
#include<unistd.h>
pid_t getpgid(pid_t pid);
/*
功能:
获取指定进程的进程组ID
参数:
pid:进程号;若为0,则功能和getpgrp一样
返回值:
成功:进程组ID
失败:-1
*/
(3)setpgid函数
#include<unistd.h>
int setpgid(pid_t pid, pid_t pgid);
/*
功能:
将进程pid的进程组改为pgid;可创建新的进程组
返回值:
成功:0
失败:-1
*/
2. 会话
概念:一个或多个进程组的集合。
创建会话注意事项:
(1)组长进程不能创建会话,否则返回出错;
(2)创建会话的非组长进程变成新会话的首进程(session header,也称为会长进程),同时会创建一个新进程组并成为组长进程(因为新会话中至少要有一个进程组);
(3)组长进程不会成为新会话首进程,新会话首进程会成为组长进程;
(4)需要root权限(Ubuntu等除外);
(5)新会话丢弃原有控制终端,该会话无控制终端;
(6)创建新会话时:先调用fork,父进程终止,子进程调用setsid(创建会话函数);
会话相关函数:
(1)getsid函数:
#include<unistd.h>
pid_t getsid(pid_t pid);
/*
功能:
获取进程所属的会话
参数:
pid:进程号;若为0则表示查看当前进程的会话ID
返回值:
成功:会话ID
失败:-1
*/
getsid示例:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
int main(int argc, const char* argv[]) {
pid_t pid = -1;
// 获取当前进程组会话ID
pid = getsid(0);
if (-1 == pid) {
perror("getsid");
return 1;
}
printf("当前进程的会话ID:%d\n", pid);
return 0;
}
运行结果:
(2)setsid函数
#include<unistd.h>
pid_t setsid(void);
/*
功能:
创建新会话,并用自己的ID设置为新进程组ID和新会话ID;
该进程将成为新进程组组成和新会话会长。
返回值:
成功:新会话ID;
失败:-1.
*/
setsid示例:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
int main(int argc, const char* argv[]) {
pid_t pid = -1;
printf("父进程pid:%d\n", getpid());
printf("父进程所属进程组的组长进程pid:%d\n", getpgrp());
printf("父进程所属会话的会长进程pid:%d\n", getsid(0));
// 创建新会话
printf("父进程%d即将创建新会话...\n", getpid());
pid = setsid(); // 失败
if (-1 == pid) {
printf("创建失败!父进程为组长进程,组长进程不可创建新会话..\n");
perror("setsid");
}
pid = fork();
if (-1 == pid) {
perror("fork");
return 1;
}
if (0 == pid) { // 子进程
printf("\n子进程创建成功!其pid:%d,其组长进程:%d\n", getpid(), getpgrp());
printf("子进程%d即将创建新会话...\n", getpid());
pid = setsid(); // 创建会话
if (-1 == pid) {
perror("setsid");
return 1;
}
printf("子进程创建新会话成功\n");
printf("子进程所属进程组的组长进程pid:%d\n", getpgrp());
printf("子进程所属会话的会长进程pid:%d\n", getsid(0));
printf("子进程的父进程pid:%d\n", getppid());
} else {
sleep(2);
printf("\n子进程创建会话后,父进程情况:\n");
printf("父进程所属进程组的组长进程pid:%d\n", getpgrp());
printf("父进程所属会话的会长进程pid:%d\n", getsid(0));
while (1) {
sleep(1);
}
}
return 0;
}
运行结果:
结果可知:
(1)组长进程不可创建新会话;
(2)非组长进程(这个示例中的子进程)创建新会话后会成为新会话的会长,同时也会创建一个新进程组并成为组长(因为新会话中至少要有一个进程组);
(3)子进程创建新会话成为新会长和新组长后,并不会影响父进程的组长和会长;
(4)父子进程可不属于同一个进程组,也可不属于同一会话。