面试题答案
一键面试1. 信号定义与注册
在Linux内核中,信号是一种异步通知机制。自定义信号需要在内核空间和用户空间进行相关操作。
内核空间
- 定义信号:
在内核源码中,信号相关定义位于
include/linux/signal.h
。要自定义信号,可以在该文件或其他合适的头文件中添加新信号定义。例如:
#define SIG_CUSTOM (SIGRTMAX + 1)
这里使用实时信号范围(SIGRTMAX
之后)来定义自定义信号,实时信号有编号范围且支持排队和优先级。
- 注册信号处理函数:
在内核模块中,通过
register_signal
函数(假设存在类似功能函数,实际内核可能需按特定接口实现)注册信号处理函数。例如:
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/signal.h>
void custom_signal_handler(int signum, siginfo_t *info, void *context) {
// 信号处理逻辑
printk(KERN_INFO "Received custom signal %d\n", signum);
}
static int __init custom_signal_init(void) {
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_sigaction = custom_signal_handler;
sa.sa_flags = SA_SIGINFO;
if (register_signal(SIG_CUSTOM, &sa) < 0) {
printk(KERN_ERR "Failed to register custom signal\n");
return -1;
}
return 0;
}
static void __exit custom_signal_exit(void) {
unregister_signal(SIG_CUSTOM);
}
module_init(custom_signal_init);
module_exit(custom_signal_exit);
MODULE_LICENSE("GPL");
用户空间
在用户空间,使用sigaction
函数注册信号处理函数。例如:
#include <stdio.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
void custom_signal_handler(int signum, siginfo_t *info, void *context) {
printf("Received custom signal %d\n", signum);
}
int main() {
struct sigaction sa;
memset(&sa, 0, sizeof(sa));
sa.sa_sigaction = custom_signal_handler;
sa.sa_flags = SA_SIGINFO;
if (sigaction(SIG_CUSTOM, &sa, NULL) < 0) {
perror("sigaction");
exit(EXIT_FAILURE);
}
// 发送信号测试
kill(getpid(), SIG_CUSTOM);
sleep(1);
return 0;
}
2. 优先级设定
实时信号的优先级由其编号决定,编号越小优先级越高。在定义SIG_CUSTOM
时选择合适的编号,如SIGRTMAX + 1
,就确定了它相对其他实时信号的优先级。
内核空间
在内核发送信号时,会根据信号编号确定优先级。例如,在send_sig_info
函数(实际内核中信号发送相关函数)中,根据信号编号进行队列插入等操作,确保高优先级信号先处理。
用户空间
用户空间无法直接修改内核信号优先级机制,但可以通过发送和处理信号的逻辑来配合优先级应用。例如,在多线程程序中,将处理高优先级信号的线程设置为高优先级调度。
3. 确保优先级在实际场景正确应用
- 信号发送与排队:内核确保按照优先级对实时信号进行排队,高优先级信号先进入队列。用户空间发送信号时,内核按优先级处理。
- 调度策略:在多任务环境中,内核调度器配合信号优先级。例如,当一个进程接收到高优先级信号时,内核调度器可以将该进程的调度优先级提高,确保其能及时处理信号。
- 测试与验证:编写测试程序,发送不同优先级的信号,观察信号处理顺序。例如,同时发送
SIG_CUSTOM
(假设优先级较高)和其他实时信号,验证SIG_CUSTOM
是否先被处理。
通过以上步骤,从信号定义、注册到优先级设定及应用,实现自定义信号在实际场景中的正确使用。