MST
星途 面试题库

面试题:C语言在Linux下实现优雅退出的信号处理机制

在Linux环境中,使用C语言编写一个程序,要求该程序能够优雅地处理常见信号(如SIGINT、SIGTERM)并实现进程的优雅退出,同时要解释信号处理函数如何与主程序逻辑进行交互,以及可能会遇到的竞态条件及解决方法。
35.6万 热度难度
编程语言C

知识考点

AI 面试

面试题答案

一键面试

C语言代码实现

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

volatile sig_atomic_t flag = 0;

void signal_handler(int signum) {
    if (signum == SIGINT || signum == SIGTERM) {
        flag = 1;
        printf("Received signal %d, preparing to exit gracefully...\n", signum);
    }
}

int main() {
    // 注册信号处理函数
    if (signal(SIGINT, signal_handler) == SIG_ERR) {
        perror("signal(SIGINT)");
        return 1;
    }
    if (signal(SIGTERM, signal_handler) == SIG_ERR) {
        perror("signal(SIGTERM)");
        return 1;
    }

    printf("Process is running. Press Ctrl+C to stop.\n");
    while (!flag) {
        // 主程序逻辑
        printf("Working...\n");
        sleep(1);
    }

    // 进行资源清理等操作
    printf("Cleaning up resources...\n");
    // 假设这里有资源清理的代码

    printf("Exiting gracefully.\n");
    return 0;
}

信号处理函数与主程序逻辑的交互

  1. 注册信号处理函数:使用signal函数为SIGINTSIGTERM信号注册处理函数signal_handler。当这些信号到达时,系统会暂停主程序的执行,跳转到信号处理函数执行。
  2. 标志位的使用:在信号处理函数中设置一个全局的volatile sig_atomic_t类型的标志位flag。这样主程序在循环中可以通过检查这个标志位来决定是否退出,从而实现了信号处理函数与主程序逻辑的通信。
  3. 主程序逻辑:主程序在while (!flag)循环中执行正常的业务逻辑。当flag被信号处理函数设置后,循环结束,主程序可以进行资源清理等收尾工作后退出。

可能遇到的竞态条件及解决方法

  1. 竞态条件:在多线程环境或者信号处理与主程序逻辑共享资源时,可能会出现竞态条件。例如,如果主程序正在读取或修改某个共享资源时,信号处理函数被触发,也对该资源进行操作,就可能导致数据不一致。
  2. 解决方法
    • 使用互斥锁:在多线程环境下,使用互斥锁(如pthread_mutex_t)来保护共享资源。在访问共享资源前加锁,访问结束后解锁。
    • 异步信号安全函数:在信号处理函数中,只调用异步信号安全的函数。例如,printf在信号处理函数中使用可能不安全,应该使用write函数代替。
    • 使用标志位和同步机制:如上述代码中,通过设置标志位来通知主程序进行资源清理,而不是在信号处理函数中直接进行复杂的资源清理操作,避免了在信号处理函数中访问共享资源带来的竞态问题。