MST

星途 面试题库

面试题:C语言Linux信号优先级与多线程编程

假设在一个多线程的C语言程序运行于Linux系统上,不同线程分别注册了不同优先级的信号处理函数,当一个高优先级信号和一个低优先级信号同时到达时,从信号处理机制和线程调度的角度分析,程序会如何响应,如何确保高优先级信号的处理不会被低优先级信号处理所干扰。
43.1万 热度难度
编程语言C

知识考点

AI 面试

面试题答案

一键面试

信号处理机制分析

  1. 信号到达时的处理:在Linux系统中,信号是异步事件,当信号到达时,内核会为接收信号的进程设置一个信号掩码,并检查进程是否正在阻塞该信号。如果进程没有阻塞信号,内核就会调用相应的信号处理函数。
  2. 信号优先级:Linux内核并没有直接支持信号的绝对优先级概念。然而,可以通过设置信号处理函数的SA_SIGINFO标志,使用sigaction函数注册信号处理函数,然后通过实时信号(RT信号,范围为34 - 64)来模拟优先级。实时信号在排队和处理上与常规信号不同,实时信号可以排队,相同的实时信号会按照发送顺序依次处理,而常规信号不会排队,相同的常规信号多次发送只会被处理一次。

线程调度角度分析

  1. 线程与信号:在多线程程序中,信号通常会被发送到整个进程,而不是特定线程。但是,线程可以通过pthread_sigmask函数阻塞或解除阻塞信号,并且可以使用pthread_kill函数向特定线程发送信号。
  2. 调度干扰:当多个信号同时到达时,由于线程共享进程的信号处理上下文,如果没有正确处理,低优先级信号处理函数可能会干扰高优先级信号处理函数的执行。例如,低优先级信号处理函数可能会占用CPU时间,导致高优先级信号处理函数不能及时执行。

确保高优先级信号处理不被干扰的方法

  1. 信号掩码与阻塞
    • 在高优先级信号处理函数执行期间,使用pthread_sigmask函数阻塞低优先级信号。例如,在高优先级信号处理函数开始时,将低优先级信号添加到线程的信号掩码中,在处理函数结束时,再将其从信号掩码中移除。
    sigset_t low_priority_mask;
    sigemptyset(&low_priority_mask);
    sigaddset(&low_priority_mask, LOW_PRIORITY_SIGNAL);
    pthread_sigmask(SIG_BLOCK, &low_priority_mask, NULL);
    // 高优先级信号处理代码
    pthread_sigmask(SIG_UNBLOCK, &low_priority_mask, NULL);
    
  2. 实时信号的使用
    • 为高优先级信号选择较高编号的实时信号(如64号),为低优先级信号选择较低编号的实时信号(如34号)。实时信号会按照发送顺序依次处理,这样可以确保高优先级信号先被处理。
    • 使用sigaction函数注册实时信号的处理函数,并设置SA_SIGINFO标志,以便能够获取信号的详细信息。
    struct sigaction sa_high;
    sa_high.sa_sigaction = high_priority_handler;
    sa_high.sa_flags = SA_SIGINFO;
    sigemptyset(&sa_high.sa_mask);
    sigaction(HIGH_PRIORITY_RT_SIGNAL, &sa_high, NULL);
    
  3. 线程优先级调度
    • 可以使用POSIX线程调度函数(如pthread_setschedparam)为处理高优先级信号的线程设置更高的调度优先级。这样,在CPU资源竞争时,高优先级信号处理线程更有可能优先执行。
    struct sched_param param;
    param.sched_priority = sched_get_priority_max(SCHED_FIFO);
    pthread_setschedparam(pthread_self(), SCHED_FIFO, &param);