MST
星途 面试题库

面试题:C语言中自定义Linux信号类型在多线程程序中的应用与问题

在一个使用C语言编写的多线程Linux程序中,要自定义一种信号类型用于线程间的同步通信。请阐述实现思路,包括如何避免信号处理函数在多线程环境下可能出现的竞态条件等问题,并给出关键代码示例。
24.4万 热度难度
编程语言C

知识考点

AI 面试

面试题答案

一键面试

实现思路

  1. 自定义信号类型:使用sigaction函数来定义信号处理函数,并指定要处理的信号。可以选择一个未被系统使用的信号编号(通常大于SIGRTMIN且小于SIGRTMAX用于实时信号)。
  2. 线程间同步通信:一个线程发送信号,另一个或多个线程接收并处理该信号。发送信号使用pthread_kill函数,它可以向指定线程发送信号。
  3. 避免竞态条件
    • 使用互斥锁:在信号处理函数中涉及共享资源访问时,使用互斥锁来保护共享资源,确保同一时间只有一个线程可以访问。
    • 信号屏蔽:在关键代码段屏蔽信号,处理完共享资源后再解除屏蔽。可以使用sigprocmask函数来实现信号屏蔽和解除屏蔽。

关键代码示例

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

// 自定义信号编号,使用实时信号
#define CUSTOM_SIGNAL SIGRTMIN

pthread_mutex_t mutex;
int shared_variable = 0;

// 信号处理函数
void signal_handler(int signum) {
    pthread_mutex_lock(&mutex);
    // 处理共享资源
    shared_variable++;
    printf("Signal received, shared_variable: %d\n", shared_variable);
    pthread_mutex_unlock(&mutex);
}

void* thread_function(void* arg) {
    // 屏蔽信号
    sigset_t set;
    sigemptyset(&set);
    sigaddset(&set, CUSTOM_SIGNAL);
    pthread_sigmask(SIG_BLOCK, &set, NULL);

    // 模拟一些工作
    sleep(2);

    // 发送信号
    pthread_kill(pthread_self(), CUSTOM_SIGNAL);

    // 解除信号屏蔽
    pthread_sigmask(SIG_UNBLOCK, &set, NULL);

    return NULL;
}

int main() {
    pthread_t thread;
    struct sigaction sa;

    // 初始化互斥锁
    pthread_mutex_init(&mutex, NULL);

    // 设置信号处理函数
    sa.sa_handler = signal_handler;
    sigemptyset(&sa.sa_mask);
    sa.sa_flags = 0;
    sigaction(CUSTOM_SIGNAL, &sa, NULL);

    // 创建线程
    pthread_create(&thread, NULL, thread_function, NULL);

    // 等待线程结束
    pthread_join(thread, NULL);

    // 销毁互斥锁
    pthread_mutex_destroy(&mutex);

    return 0;
}

在上述代码中:

  1. 自定义信号处理函数signal_handler函数在接收到自定义信号CUSTOM_SIGNAL时,对共享变量shared_variable进行操作,并使用互斥锁保护。
  2. 线程函数thread_function函数中,首先屏蔽信号,进行一些工作后发送信号,最后解除信号屏蔽。
  3. 主线程:在主线程中,初始化互斥锁,设置信号处理函数,创建并等待线程结束,最后销毁互斥锁。