MST

星途 面试题库

面试题:C语言中信号掩码与信号集操作在复杂场景下的应用

在一个多线程的Linux C程序中,主线程负责初始化资源,子线程执行核心业务逻辑。在业务逻辑执行过程中,可能会收到多种信号(如SIGTERM、SIGUSR1等)。请阐述如何通过合理使用信号掩码与信号集操作,确保在收到信号时,主线程能够安全地清理资源,子线程能够正确处理信号,且整个程序不会出现数据竞争或未定义行为。请给出具体的代码框架及关键操作步骤说明。
13.6万 热度难度
编程语言C

知识考点

AI 面试

面试题答案

一键面试

关键操作步骤说明

  1. 信号处理函数的定义
    • 定义主线程用于清理资源的信号处理函数,例如对于SIGTERM信号,在处理函数中进行资源清理操作。
    • 定义子线程用于处理业务相关信号(如SIGUSR1)的信号处理函数,在处理函数中完成相应业务逻辑。
  2. 信号集的初始化
    • 创建一个信号集用于阻塞信号,初始化该信号集,将需要处理的信号(如SIGTERMSIGUSR1)添加到信号集中。
  3. 主线程操作
    • 在主线程初始化资源之前,使用sigprocmask函数将信号集设置为阻塞状态,防止信号在资源未初始化完成时干扰。
    • 初始化资源。
    • 解除对信号的阻塞,使主线程能够接收信号并调用相应的信号处理函数进行资源清理。
  4. 子线程操作
    • 子线程在启动时,同样使用sigprocmask函数将信号集设置为阻塞状态。
    • 子线程执行核心业务逻辑。
    • 在业务逻辑中,使用sigwait函数等待特定信号(如SIGUSR1),当信号到达时,sigwait函数返回,子线程调用相应的信号处理函数处理信号。

代码框架

#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <signal.h>
#include <unistd.h>

// 信号处理函数声明
void handle_term(int signum);
void handle_usr1(int signum);

// 全局变量,假设为需要清理的资源
int resource = 0;

void* thread_function(void* arg) {
    sigset_t *set = (sigset_t *)arg;
    int signum;

    // 子线程阻塞信号
    if (sigprocmask(SIG_SETMASK, set, NULL) == -1) {
        perror("sigprocmask");
        pthread_exit(NULL);
    }

    // 核心业务逻辑
    while (1) {
        // 等待SIGUSR1信号
        if (sigwait(set, &signum) != 0) {
            perror("sigwait");
            pthread_exit(NULL);
        }
        if (signum == SIGUSR1) {
            handle_usr1(signum);
        }
    }
    pthread_exit(NULL);
}

int main() {
    pthread_t tid;
    sigset_t set;

    // 初始化信号集
    sigemptyset(&set);
    sigaddset(&set, SIGTERM);
    sigaddset(&set, SIGUSR1);

    // 主线程阻塞信号
    if (sigprocmask(SIG_SETMASK, &set, NULL) == -1) {
        perror("sigprocmask");
        return 1;
    }

    // 初始化资源
    resource = 1;

    // 创建子线程
    if (pthread_create(&tid, NULL, thread_function, (void *)&set) != 0) {
        perror("pthread_create");
        return 1;
    }

    // 主线程解除对信号的阻塞
    if (sigprocmask(SIG_UNBLOCK, &set, NULL) == -1) {
        perror("sigprocmask");
        return 1;
    }

    // 注册信号处理函数
    struct sigaction sa_term;
    sa_term.sa_handler = handle_term;
    sigemptyset(&sa_term.sa_mask);
    sa_term.sa_flags = 0;
    if (sigaction(SIGTERM, &sa_term, NULL) == -1) {
        perror("sigaction");
        return 1;
    }

    struct sigaction sa_usr1;
    sa_usr1.sa_handler = handle_usr1;
    sigemptyset(&sa_usr1.sa_mask);
    sa_usr1.sa_flags = 0;
    if (sigaction(SIGUSR1, &sa_usr1, NULL) == -1) {
        perror("sigaction");
        return 1;
    }

    // 主线程等待子线程结束
    if (pthread_join(tid, NULL) != 0) {
        perror("pthread_join");
        return 1;
    }

    return 0;
}

void handle_term(int signum) {
    // 清理资源
    printf("Handling SIGTERM, cleaning up resource...\n");
    resource = 0;
}

void handle_usr1(int signum) {
    // 处理SIGUSR1信号相关业务逻辑
    printf("Handling SIGUSR1 in sub - thread...\n");
}