exit_group系统调用及示例

exit_group – 终止线程组

函数介绍

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

函数原型

#include <sys/syscall.h>
#include <unistd.h>

void exit_group(int status);

功能

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

参数

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

返回值

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

特殊限制

  • 是Linux特有的系统调用
  • 需要通过syscall调用
  • 终止整个线程组,不只是当前线程

相似函数

  • exit(): 终止当前进程(单线程环境)
  • _exit(): 立即终止当前进程
  • pthread_exit(): 终止当前线程

示例代码

#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;
}
此条目发表在linux文章分类目录。将固定链接加入收藏夹。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注