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[3]; int thread_ids[3] = {1, 2, 3}; // 创建多个线程 for (int i = 0; i < 3; i++) { if (pthread_create(&threads[i], NULL, thread_function, &thread_ids[i]) != 0) { perror("创建线程失败"); exit(EXIT_FAILURE); } printf("创建线程 %d\n", thread_ids[i]); } // 等待线程(实际上不会等到,因为线程2会调用exit_group) printf("主线程等待子线程...\n"); // 这里程序会因为exit_group而终止,不会执行到下面 for (int i = 0; i < 3; i++) { pthread_join(threads[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[2]; // 线程1 pthread_create(&threads[0], NULL, [](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[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; }
|