exit_group系统调用及示例

exit_group - 终止线程组

函数介绍

exit_group是一个Linux系统调用,用于终止整个线程组(进程组),而不仅仅是当前线程。它是多线程程序中用于整体退出的重要机制。

函数原型

1
2
3
4
5
#include <sys/syscall.h>
#include <unistd.h>

void exit_group(int status);

功能

终止调用线程所属的整个线程组,所有线程都会退出。

参数

  • int status: 退出状态码,传递给父进程

返回值

  • 无返回值(函数不返回)

特殊限制

  • 是Linux特有的系统调用

  • 需要通过syscall调用

  • 终止整个线程组,不只是当前线程

相似函数

  • exit(): 终止当前进程(单线程环境)

  • _exit(): 立即终止当前进程

  • pthread_exit(): 终止当前线程

示例代码

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
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/syscall.h>
#include <pthread.h>
#include <sys/wait.h>
#include <errno.h>
#include <string.h>

// 系统调用包装
static void exit_group_wrapper(int status) {
syscall(__NR_exit_group, status);
}

// 线程函数
void* thread_function(void* arg) {
int thread_id = *(int*)arg;

printf("线程 %d 启动\n", thread_id);

// 模拟工作
sleep(1);

if (thread_id == 2) {
printf("线程 %d 调用exit_group,整个线程组将退出\n", thread_id);
exit_group_wrapper(42); // 整个进程组退出
// 下面的代码不会执行
printf("这行代码不会被执行\n");
}

// 其他线程继续工作
sleep(2);
printf("线程 %d 完成工作\n", thread_id);

return NULL;
}

int main() {
printf("=== Exit_group 函数示例 ===\n");
printf("当前进程PID: %d\n", getpid());

// 示例1: 多线程环境中的exit_group
printf("\n示例1: 多线程环境中的exit_group\n");

pthread_t threads&#91;3];
int thread_ids&#91;3] = {1, 2, 3};

// 创建多个线程
for (int i = 0; i < 3; i++) {
if (pthread_create(&threads&#91;i], NULL, thread_function, &thread_ids&#91;i]) != 0) {
perror("创建线程失败");
exit(EXIT_FAILURE);
}
printf("创建线程 %d\n", thread_ids&#91;i]);
}

// 等待线程(实际上不会等到,因为线程2会调用exit_group)
printf("主线程等待子线程...\n");

// 这里程序会因为exit_group而终止,不会执行到下面
for (int i = 0; i < 3; i++) {
pthread_join(threads&#91;i], NULL);
}

printf("所有线程完成\n"); // 这行不会执行
return 0; // 这行也不会执行
}

// 单独的测试函数
void test_exit_group_behavior() {
printf("\n=== Exit_group 行为测试 ===\n");

pid_t pid = fork();
if (pid == -1) {
perror("fork失败");
return;
}

if (pid == 0) {
// 子进程
printf("子进程PID: %d\n", getpid());

// 创建多个线程
pthread_t threads&#91;2];

// 线程1
pthread_create(&threads&#91;0], NULL, &#91;](void* arg) -> void* {
printf("线程1开始工作\n");
sleep(3); // 比主线程工作时间长
printf("线程1完成工作\n"); // 这行可能不会执行
return NULL;
}, NULL);

// 线程2(主线程模拟)
printf("主线程工作1秒后调用exit_group\n");
sleep(1);

printf("调用exit_group(100)\n");
exit_group_wrapper(100);

// 这些代码不会执行
printf("这行不会被执行\n");
pthread_join(threads&#91;0], NULL);

} else {
// 父进程等待子进程
int status;
pid_t result = waitpid(pid, &status, 0);
if (result != -1) {
if (WIFEXITED(status)) {
int exit_code = WEXITSTATUS(status);
printf("子进程通过exit_group退出,退出码: %d\n", exit_code);
} else if (WIFSIGNALED(status)) {
int signal = WTERMSIG(status);
printf("子进程被信号 %d 终止\n", signal);
}
}
}
}

// exit vs exit_group 对比
void compare_exit_functions() {
printf("\n=== Exit vs Exit_group 对比 ===\n");

printf("exit() 行为:\n");
printf(" - 单线程: 终止整个进程\n");
printf(" - 多线程: 终止调用线程,其他线程继续运行\n");
printf(" - 执行清理函数\n");
printf(" - 刷新缓冲区\n\n");

printf("exit_group() 行为:\n");
printf(" - 单线程: 终止整个进程\n");
printf(" - 多线程: 终止整个线程组(所有线程)\n");
printf(" - 不执行清理函数\n");
printf(" - 不刷新缓冲区\n");
printf(" - 立即终止\n\n");

printf("pthread_exit() 行为:\n");
printf(" - 终止调用线程\n");
printf(" - 其他线程继续运行\n");
printf(" - 如果是最后一个线程,终止进程\n\n");
}

// 实际应用场景演示
void demonstrate_real_world_usage() {
printf("\n=== 实际应用场景 ===\n");

printf("exit_group的典型使用场景:\n");
printf("1. 多线程程序的整体错误处理\n");
printf("2. 资源严重不足时的紧急退出\n");
printf("3. 接收到致命信号时\n");
printf("4. 线程检测到不可恢复的错误\n\n");

// 模拟错误处理场景
printf("错误处理示例:\n");
printf("void handle_critical_error(int error_code) {\n");
printf(" log_error(\"严重错误: %%d\\n\", error_code);\n");
printf(" // 通知所有线程立即退出\n");
printf(" exit_group(error_code);\n");
printf("}\n\n");

printf("信号处理示例:\n");
printf("void signal_handler(int sig) {\n");
printf(" if (sig == SIGSEGV || sig == SIGBUS) {\n");
printf(" // 段错误,立即退出整个进程\n");
printf(" exit_group(128 + sig);\n");
printf(" }\n");
printf("}\n\n");
}

// 测试exit_group与信号的关系
void test_exit_group_with_signals() {
printf("\n=== Exit_group 与信号 ===\n");

printf("exit_group与信号的关系:\n");
printf("1. exit_group不被信号中断\n");
printf("2. 调用后立即终止,不处理待处理信号\n");
printf("3. 退出状态通过wait机制传递\n");
printf("4. 不执行信号处理程序\n\n");

// 演示信号处理
printf("信号处理中的使用:\n");
printf("在信号处理程序中使用exit_group:\n");
printf("void sigsegv_handler(int sig) {\n");
printf(" write(STDERR_FILENO, \"段错误!\\n\", 8);\n");
printf(" exit_group(128 + SIGSEGV);\n");
printf("}\n\n");
}

int main_comprehensive_test() {
printf("=== Exit_group 完整测试 ===\n");

// 运行各个测试
test_exit_group_behavior();
compare_exit_functions();
demonstrate_real_world_usage();
test_exit_group_with_signals();

printf("\n=== 总结 ===\n");
printf("exit_group的特点:\n");
printf("1. Linux特有系统调用\n");
printf("2. 终止整个线程组\n");
printf("3. 立即终止,不执行清理\n");
printf("4. 不刷新缓冲区\n");
printf("5. 适用于紧急退出场景\n\n");

printf("使用场景:\n");
printf("1. 多线程程序整体退出\n");
printf("2. 严重错误的紧急处理\n");
printf("3. 信号处理中的快速退出\n");
printf("4. 资源不足时的优雅退出\n\n");

printf("注意事项:\n");
printf("1. 需要通过syscall调用\n");
printf("2. 不执行atexit注册的函数\n");
printf("3. 不刷新标准I/O缓冲区\n");
printf("4. 所有线程立即终止\n");
printf("5. 慎重使用,可能导致数据丢失\n\n");

printf("与相关函数的区别:\n");
printf("- exit(): 执行清理,适用于正常退出\n");
printf("- _exit(): 立即退出,但只影响当前线程\n");
printf("- exit_group(): 立即退出整个线程组\n");
printf("- pthread_exit(): 只退出当前线程\n\n");

return 0;
}

https://www.calcguide.tech/2025/08/09/exit-group系统调用及示例

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