setpgid系统调用及示例

setpgid 函数详解

setpgid 是Linux系统调用,用于设置进程的进程组ID(Process Group ID)。进程组是进程的集合,用于信号分发和作业控制。通过设置进程组,可以将相关进程组织在一起,便于统一管理和控制。

  1. 函数介绍

setpgid 是Linux系统调用,用于设置进程的进程组ID(Process Group ID)。进程组是进程的集合,用于信号分发和作业控制。通过设置进程组,可以将相关进程组织在一起,便于统一管理和控制。

data-ad-format="fluid" data-ad-layout-key="-7k+ex-4a-9w+4a">

setpgid系统调用LinuxGuide

setpgid系统调用及示例_setpgid函数作用-CSDN博客

  1. 函数原型
1
2
3
#include <unistd.h>
int setpgid(pid_t pid, pid_t pgid);

  1. 功能

setpgid 将指定进程(由pid标识)加入到指定的进程组(由pgid标识)。如果进程组不存在,则创建新的进程组。这个函数主要用于作业控制和信号管理。

  1. 参数
  • pid_t pid: 目标进程ID(0表示当前进程)

  • pid_t pgid: 进程组ID(0表示使用pid作为进程组ID)

  1. 返回值
  • 成功: 返回0

  • 失败: 返回-1,并设置errno

  1. 相似函数,或关联函数
  • getpgid: 获取进程的进程组ID

  • setpgrp: 设置进程组(等同于setpgid(0,0))

  • getsid: 获取会话ID

  • setsid: 创建新会话

  1. 示例代码

示例1:基础setpgid使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/wait.h>

/**
* 显示进程组信息
*/
void show_process_group_info() {
pid_t pid = getpid();
pid_t pgid = getpgid(0);
pid_t ppid = getppid();

printf("进程ID: %d\n", pid);
printf("父进程ID: %d\n", ppid);
printf("进程组ID: %d\n", pgid);
printf("会话ID: %d\n", getsid(0));
printf("\n");
}

/**
* 演示基础setpgid使用方法
*/
int demo_setpgid_basic() {
pid_t original_pgid, new_pgid;
int result;

printf("=== 基础setpgid使用示例 ===\n");

// 显示原始进程组信息
printf("1. 原始进程组信息:\n");
show_process_group_info();
original_pgid = getpgid(0);

// 将当前进程移动到新的进程组
printf("2. 创建新的进程组:\n");
pid_t new_group_id = getpid(); // 使用当前进程ID作为新进程组ID

printf(" 尝试将进程 %d 移动到进程组 %d\n", getpid(), new_group_id);
result = setpgid(0, new_group_id);

if (result == 0) {
printf(" ✓ 成功创建并加入新进程组\n");

// 验证设置结果
new_pgid = getpgid(0);
printf(" 新的进程组ID: %d\n", new_pgid);

if (new_pgid == new_group_id) {
printf(" ✓ 进程组设置正确\n");
} else {
printf(" ✗ 进程组设置可能有问题\n");
}

show_process_group_info();
} else {
printf(" ✗ 创建新进程组失败: %s\n", strerror(errno));
if (errno == EACCES) {
printf(" 原因:不允许从会话领导进程更改进程组\n");
} else if (errno == EINVAL) {
printf(" 原因:进程ID或进程组ID无效\n");
} else if (errno == EPERM) {
printf(" 原因:权限不足\n");
} else if (errno == ESRCH) {
printf(" 原因:指定的进程不存在\n");
}
}

return 0;
}

int main() {
return demo_setpgid_basic();
}

示例2:父子进程组管理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/wait.h>

/**
* 子进程函数
*/
void child_process(int child_id) {
printf("子进程 %d 启动\n", getpid());
printf(" 子进程 %d 的原始进程组: %d\n", getpid(), getpgid(0));

// 子进程创建自己的进程组
pid_t new_pgid = getpid();
printf(" 子进程 %d 尝试创建新进程组: %d\n", getpid(), new_pgid);

int result = setpgid(0, new_pgid);
if (result == 0) {
printf(" ✓ 子进程 %d 成功创建新进程组\n", getpid());
printf(" 子进程 %d 当前进程组: %d\n", getpid(), getpgid(0));
} else {
printf(" ✗ 子进程 %d 创建新进程组失败: %s\n", getpid(), strerror(errno));
}

// 模拟一些工作
sleep(3);
printf("子进程 %d 结束\n", getpid());
exit(0);
}

/**
* 演示父子进程组管理
*/
int demo_parent_child_groups() {
pid_t child1_pid, child2_pid;
pid_t original_pgid;

printf("=== 父子进程组管理演示 ===\n");

// 显示父进程信息
printf("父进程信息:\n");
printf(" 进程ID: %d\n", getpid());
printf(" 原始进程组: %d\n", getpgid(0));
printf(" 会话ID: %d\n", getsid(0));
printf("\n");

// 创建第一个子进程
printf("1. 创建第一个子进程:\n");
child1_pid = fork();
if (child1_pid == 0) {
child_process(1);
} else if (child1_pid > 0) {
printf(" 父进程创建子进程1: PID=%d\n", child1_pid);
printf(" 子进程1的进程组: %d\n", getpgid(child1_pid));
} else {
perror("创建子进程1失败");
return -1;
}

// 创建第二个子进程
printf("\n2. 创建第二个子进程:\n");
child2_pid = fork();
if (child2_pid == 0) {
child_process(2);
} else if (child2_pid > 0) {
printf(" 父进程创建子进程2: PID=%d\n", child2_pid);
printf(" 子进程2的进程组: %d\n", getpgid(child2_pid));
} else {
perror("创建子进程2失败");
// 清理已创建的子进程
kill(child1_pid, SIGKILL);
return -1;
}

// 父进程也创建新进程组
printf("\n3. 父进程创建新进程组:\n");
original_pgid = getpgid(0);
pid_t parent_pgid = getpid();

printf(" 父进程尝试创建新进程组: %d\n", parent_pgid);
int result = setpgid(0, parent_pgid);
if (result == 0) {
printf(" ✓ 父进程成功创建新进程组\n");
printf(" 父进程当前进程组: %d\n", getpgid(0));
} else {
printf(" ✗ 父进程创建新进程组失败: %s\n", strerror(errno));
}

// 等待子进程结束
printf("\n4. 等待子进程结束:\n");
int status;
pid_t finished_pid;

while ((finished_pid = wait(&status)) > 0) {
printf(" 子进程 %d 已结束,退出状态: %d\n", finished_pid, WEXITSTATUS(status));
}

// 恢复父进程原始进程组
printf("\n5. 恢复父进程原始进程组:\n");
result = setpgid(0, original_pgid);
if (result == 0) {
printf(" ✓ 父进程成功恢复原始进程组: %d\n", getpgid(0));
} else {
printf(" ✗ 父进程恢复原始进程组失败: %s\n", strerror(errno));
}

return 0;
}

int main() {
return demo_parent_child_groups();
}

示例3:进程组信号处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/wait.h>
#include <signal.h>

/**
* 信号处理函数
*/
void signal_handler(int sig) {
printf("进程 %d 接收到信号 %d (%s)\n", getpid(), sig, strsignal(sig));
}

/**
* 工作进程函数
*/
void worker_process(int worker_id) {
// 设置信号处理
signal(SIGTERM, signal_handler);
signal(SIGINT, signal_handler);
signal(SIGUSR1, signal_handler);

printf("工作进程 %d 启动,进程组: %d\n", getpid(), getpgid(0));

// 创建自己的进程组
pid_t new_pgid = getpid();
if (setpgid(0, new_pgid) == 0) {
printf("工作进程 %d 成功创建进程组: %d\n", getpid(), new_pgid);
}

// 模拟长时间工作
for (int i = 0; i < 10; i++) {
printf("工作进程 %d 正在工作... (%d/10)\n", getpid(), i + 1);
sleep(2);
}

printf("工作进程 %d 结束\n", getpid());
exit(0);
}

/**
* 演示进程组信号处理
*/
int demo_process_group_signaling() {
pid_t workers&#91;3];
pid_t original_pgid;

printf("=== 进程组信号处理演示 ===\n");

// 保存原始进程组
original_pgid = getpgid(0);
printf("主进程原始进程组: %d\n", original_pgid);

// 创建工作进程组
printf("\n1. 创建工作进程组:\n");
for (int i = 0; i < 3; i++) {
workers&#91;i] = fork();
if (workers&#91;i] == 0) {
worker_process(i + 1);
} else if (workers&#91;i] > 0) {
printf(" 创建工作进程 %d: PID=%d\n", i + 1, workers&#91;i]);

// 将子进程加入同一进程组
pid_t group_id = workers&#91;0]; // 使用第一个子进程的PID作为组ID
if (setpgid(workers&#91;i], group_id) == 0) {
printf(" 工作进程 %d 加入进程组: %d\n", workers&#91;i], group_id);
} else {
printf(" 工作进程 %d 加入进程组失败: %s\n", workers&#91;i], strerror(errno));
}
} else {
perror("创建工作进程失败");
// 清理已创建的进程
for (int j = 0; j < i; j++) {
kill(workers&#91;j], SIGKILL);
}
return -1;
}
}

// 显示进程组信息
printf("\n2. 进程组信息:\n");
for (int i = 0; i < 3; i++) {
pid_t pgid = getpgid(workers&#91;i]);
printf(" 工作进程 %d (PID=%d) 进程组: %d\n", i + 1, workers&#91;i], pgid);
}

// 等待一段时间后发送信号
printf("\n3. 等待5秒后发送信号到进程组...\n");
sleep(5);

// 向进程组发送信号(发送给组内所有进程)
pid_t target_group = getpgid(workers&#91;0]);
printf("向进程组 %d 发送 SIGUSR1 信号\n", target_group);

if (kill(-target_group, SIGUSR1) == 0) { // 负数表示发送给整个进程组
printf("✓ 成功发送信号到进程组\n");
} else {
printf("✗ 发送信号失败: %s\n", strerror(errno));
}

// 等待一段时间观察信号处理
sleep(3);

// 发送终止信号
printf("\n4. 发送终止信号:\n");
printf("向进程组 %d 发送 SIGTERM 信号\n", target_group);

if (kill(-target_group, SIGTERM) == 0) {
printf("✓ 成功发送终止信号\n");
} else {
printf("✗ 发送终止信号失败: %s\n", strerror(errno));
}

// 等待所有工作进程结束
printf("\n5. 等待工作进程结束:\n");
int status;
pid_t finished_pid;
int finished_count = 0;

while (finished_count < 3) {
finished_pid = wait(&status);
if (finished_pid > 0) {
finished_count++;
printf(" 工作进程 %d 已结束,退出状态: %d\n",
finished_pid, WEXITSTATUS(status));
} else {
break;
}
}

printf("所有工作进程已完成\n");
return 0;
}

int main() {
return demo_process_group_signaling();
}

示例4:会话和进程组管理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/wait.h>
#include <signal.h>

/**
* 显示会话和进程组信息
*/
void show_session_info() {
printf("=== 会话和进程组信息 ===\n");
printf("进程ID: %d\n", getpid());
printf("父进程ID: %d\n", getppid());
printf("进程组ID: %d\n", getpgid(0));
printf("会话ID: %d\n", getsid(0));
printf("前台进程组: %d\n", tcgetpgrp(STDIN_FILENO));
printf("\n");
}

/**
* 会话领导进程
*/
void session_leader() {
printf("会话领导进程启动 (PID: %d)\n", getpid());
show_session_info();

// 创建新会话
pid_t sid = setsid();
if (sid != -1) {
printf("✓ 成功创建新会话: %d\n", sid);
show_session_info();
} else {
printf("✗ 创建新会话失败: %s\n", strerror(errno));
exit(1);
}

// 创建子进程组
for (int i = 0; i < 2; i++) {
pid_t child_pid = fork();
if (child_pid == 0) {
// 子进程
printf("子进程 %d 启动\n", getpid());

// 创建自己的进程组
pid_t new_pgid = getpid();
if (setpgid(0, new_pgid) == 0) {
printf("子进程 %d 成功创建进程组: %d\n", getpid(), new_pgid);
}

// 模拟工作
for (int j = 0; j < 5; j++) {
printf("子进程 %d 工作中... (%d/5)\n", getpid(), j + 1);
sleep(2);
}

printf("子进程 %d 结束\n", getpid());
exit(0);
} else if (child_pid > 0) {
printf("会话领导进程创建子进程: %d\n", child_pid);

// 将子进程加入特定进程组
if (setpgid(child_pid, child_pid) == 0) {
printf("子进程 %d 加入进程组成功\n", child_pid);
}
}
}

// 等待子进程结束
int status;
pid_t finished_pid;
while ((finished_pid = wait(&status)) > 0) {
printf("子进程 %d 已结束\n", finished_pid);
}

printf("会话领导进程结束\n");
exit(0);
}

/**
* 演示会话和进程组管理
*/
int demo_session_management() {
pid_t session_leader_pid;

printf("=== 会话和进程组管理演示 ===\n");

// 显示初始信息
printf("1. 初始进程信息:\n");
show_session_info();

// 创建会话领导进程
printf("2. 创建会话领导进程:\n");
session_leader_pid = fork();
if (session_leader_pid == 0) {
session_leader();
} else if (session_leader_pid > 0) {
printf("主进程创建会话领导进程: %d\n", session_leader_pid);

// 等待会话领导进程结束
int status;
waitpid(session_leader_pid, &status, 0);
printf("会话领导进程已结束\n");
} else {
perror("创建会话领导进程失败");
return -1;
}

// 显示最终信息
printf("\n3. 最终进程信息:\n");
show_session_info();

return 0;
}

int main() {
return demo_session_management();
}

示例5:作业控制演示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <sys/wait.h>
#include <signal.h>

/**
* 后台作业进程
*/
void background_job(int job_id) {
printf("后台作业 %d 启动 (PID: %d)\n", job_id, getpid());

// 创建独立的进程组
if (setpgid(0, 0) == 0) {
printf("后台作业 %d 成功创建进程组\n", job_id);
} else {
printf("后台作业 %d 创建进程组失败: %s\n", job_id, strerror(errno));
}

// 模拟长时间运行的作业
for (int i = 0; i < 20; i++) {
printf("后台作业 %d 运行中... (%d/20)\n", job_id, i + 1);
sleep(1);

// 检查是否收到终止信号
if (i == 10) {
// 模拟作业暂停和恢复
printf("后台作业 %d 暂停工作\n", job_id);
sleep(2);
printf("后台作业 %d 恢复工作\n", job_id);
}
}

printf("后台作业 %d 完成\n", job_id);
exit(0);
}

/**
* 作业控制管理器
*/
typedef struct {
pid_t pid;
int job_id;
int status; // 0:运行, 1:暂停, 2:完成
char command&#91;256];
} job_t;

/**
* 显示作业列表
*/
void show_job_list(job_t *jobs, int count) {
printf("\n=== 作业列表 ===\n");
printf("%-5s %-8s %-10s %s\n", "作业ID", "进程ID", "状态", "命令");
printf("----------------------------------------\n");

for (int i = 0; i < count; i++) {
const char *status_str;
switch (jobs&#91;i].status) {
case 0: status_str = "运行"; break;
case 1: status_str = "暂停"; break;
case 2: status_str = "完成"; break;
default: status_str = "未知"; break;
}

printf("%-5d %-8d %-10s %s\n",
jobs&#91;i].job_id, jobs&#91;i].pid, status_str, jobs&#91;i].command);
}
printf("\n");
}

/**
* 演示作业控制
*/
int demo_job_control() {
job_t jobs&#91;3];
int job_count = 0;

printf("=== 作业控制演示 ===\n");

// 创建后台作业
printf("1. 创建后台作业:\n");
for (int i = 0; i < 3; i++) {
pid_t job_pid = fork();
if (job_pid == 0) {
background_job(i + 1);
} else if (job_pid > 0) {
// 父进程记录作业信息
jobs&#91;job_count].pid = job_pid;
jobs&#91;job_count].job_id = i + 1;
jobs&#91;job_count].status = 0; // 运行中
snprintf(jobs&#91;job_count].command, sizeof(jobs&#91;job_count].command),
"background_job_%d", i + 1);
job_count++;

printf(" 创建后台作业 %d: PID=%d\n", i + 1, job_pid);

// 将子进程加入独立进程组
if (setpgid(job_pid, job_pid) == 0) {
printf(" 作业 %d 成功创建独立进程组\n", i + 1);
}
} else {
perror("创建后台作业失败");
}
}

// 显示初始作业列表
show_job_list(jobs, job_count);

// 演示向特定作业发送信号
printf("2. 向作业发送信号:\n");
if (job_count > 0) {
printf(" 向作业 1 (PID=%d) 发送 SIGUSR1 信号\n", jobs&#91;0].pid);
if (kill(jobs&#91;0].pid, SIGUSR1) == 0) {
printf(" ✓ 信号发送成功\n");
} else {
printf(" ✗ 信号发送失败: %s\n", strerror(errno));
}
}

// 等待一段时间
printf("\n3. 等待作业运行...\n");
sleep(5);

// 显示当前作业状态
show_job_list(jobs, job_count);

// 演示作业控制操作
printf("4. 作业控制操作:\n");

// 暂停一个作业
if (job_count > 1) {
printf(" 暂停作业 2 (PID=%d)\n", jobs&#91;1].pid);
if (kill(-getpgid(jobs&#91;1].pid), SIGSTOP) == 0) { // 发送给整个进程组
jobs&#91;1].status = 1; // 暂停
printf(" ✓ 作业 2 已暂停\n");
} else {
printf(" ✗ 暂停作业 2 失败: %s\n", strerror(errno));
}
}

// 显示更新后的作业列表
show_job_list(jobs, job_count);

// 恢复暂停的作业
if (job_count > 1) {
printf(" 恢复作业 2 (PID=%d)\n", jobs&#91;1].pid);
if (kill(-getpgid(jobs&#91;1].pid), SIGCONT) == 0) {
jobs&#91;1].status = 0; // 运行中
printf(" ✓ 作业 2 已恢复\n");
} else {
printf(" ✗ 恢复作业 2 失败: %s\n", strerror(errno));
}
}

// 等待所有作业完成
printf("\n5. 等待所有作业完成:\n");
int completed_jobs = 0;
while (completed_jobs < job_count) {
int status;
pid_t finished_pid = waitpid(-1, &status, WNOHANG);
if (finished_pid > 0) {
// 找到完成的作业并更新状态
for (int i = 0; i < job_count; i++) {
if (jobs&#91;i].pid == finished_pid) {
jobs&#91;i].status = 2; // 完成
printf(" 作业 %d (PID=%d) 已完成\n", jobs&#91;i].job_id, finished_pid);
completed_jobs++;
break;
}
}
} else if (finished_pid == 0) {
// 没有作业完成,短暂等待
usleep(100000); // 100ms
} else {
// 错误
if (errno != ECHILD) {
perror("等待作业完成时出错");
}
break;
}
}

// 显示最终作业列表
show_job_list(jobs, job_count);

printf("作业控制演示完成\n");
return 0;
}

int main() {
return demo_job_control();
}

setpgid 使用注意事项

系统要求:

内核版本: 支持进程组管理的Linux内核

权限要求: 通常不需要特殊权限

架构支持: 支持所有主流架构

参数规则:

pid为0: 表示当前进程

pgid为0: 表示使用pid作为进程组ID

进程限制: 只能操作当前会话中的进程

会话限制: 不能将进程移到不同会话的进程组

错误处理:

EACCES: 不允许从会话领导进程更改进程组

EINVAL: 进程ID或进程组ID无效

EPERM: 权限不足

ESRCH: 指定的进程不存在

性能考虑:

系统调用开销: 频繁调用有性能开销

内核数据结构: 需要更新内核中的进程组信息

同步操作: 涉及内核数据结构的同步更新

安全考虑:

进程控制: 可能影响其他进程的行为

信号传播: 进程组信号会影响组内所有进程

会话管理: 不当的会话操作可能影响终端控制

最佳实践:

时机选择: 在进程创建后尽早设置进程组

错误处理: 妥善处理各种错误情况

状态检查: 验证设置结果的正确性

资源清理: 及时清理不需要的进程组

文档记录: 记录进程组管理策略

进程组和会话概念

进程组(Process Group):

  • 定义: 一组相关进程的集合

  • 用途: 信号分发、作业控制

  • 特点: 同一进程组的进程可以被统一控制

会话(Session):

  • 定义: 一个或多个进程组的集合

  • 用途: 终端控制、登录会话管理

  • 特点: 会话领导进程控制整个会话

关系层次:

1
2
3
4
会话 (Session)
└── 进程组 (Process Group)
└── 进程 (Process)

常见使用场景

1. Shell作业控制:

1
2
3
// 创建后台作业的独立进程组
setpgid(child_pid, child_pid);

2. 守护进程:

1
2
3
// 创建独立会话,脱离控制终端
setsid();

3. 多进程应用:

1
2
3
// 将相关进程组织到同一进程组
setpgid(worker_pid, group_leader_pid);

信号与进程组

组信号发送:

1
2
3
// 向整个进程组发送信号
kill(-pgid, SIGTERM);

前台进程组:

1
2
3
// 设置前台进程组(控制终端)
tcsetpgrp(STDIN_FILENO, pgid);

总结

setpgid 是Linux系统中重要的进程管理函数,提供了:

进程组控制: 灵活的进程组管理能力

作业控制: 支持shell风格的作业控制

信号管理: 便于向进程组发送信号

会话管理: 支持会话和终端控制

通过合理使用 setpgid,可以构建更加灵活和可控的多进程应用程序。在实际应用中,需要注意进程组的生命周期管理、错误处理和信号控制等关键问题。

data-ad-format="auto" data-full-width-responsive="true">