该程序向自身发送实时信号并处理它们。一旦处理完毕,它就会按照收到的顺序输出收到的信号。
$ cat realtime.c
#include <signal.h>
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int received_signals[10];
int received_signals_value[10];
int received_signals_count = 0;
void real_time_handler(int sig_number, siginfo_t * info,
void * arg __attribute__ ((unused)))
{
received_signals[received_signals_count] = sig_number - SIGRTMIN;
received_signals_value[received_signals_count] = info->si_value.sival_int;
++received_signals_count;
}
void send_real_time_signal(int sig_number, int value)
{
union sigval sig_value;
printf("Sending signal SIRTMIN+%d, value %d\n", sig_number, value);
sig_value.sival_int = value;
if (sigqueue(getpid(), sig_number + SIGRTMIN, sig_value) < 0) {
perror("sigqueue");
exit(EXIT_FAILURE);
}
}
int main()
{
struct sigaction action;
sigset_t set;
int i;
// Handler setup
action.sa_sigaction = real_time_handler;
sigemptyset(&action.sa_mask);
action.sa_flags = SA_SIGINFO;
if ((sigaction(SIGRTMIN + 1, & action, NULL) < 0)
|| (sigaction(SIGRTMIN + 2, & action, NULL) < 0)
|| (sigaction(SIGRTMIN + 3, & action, NULL) < 0)) {
perror("sigaction");
exit(EXIT_FAILURE);
}
// Block all signals
sigfillset(&set);
sigprocmask(SIG_BLOCK, &set, NULL);
send_real_time_signal(1, 0);
send_real_time_signal(2, 1);
send_real_time_signal(3, 2);
send_real_time_signal(1, 3);
send_real_time_signal(2, 4);
send_real_time_signal(3, 5);
send_real_time_signal(3, 6);
send_real_time_signal(2, 7);
send_real_time_signal(1, 8);
send_real_time_signal(3, 9);
// Unblock all signals
sigfillset(&set);
sigprocmask(SIG_UNBLOCK, &set, NULL);
// To make sure we're handling all signals before resuming
sleep(1);
// Display results
for (i = 0; i < received_signals_count; ++i) {
printf("Received signal SIGRTMIN+%d, value %d\n",
received_signals[i], received_signals_value[i]);
}
return EXIT_SUCCESS;
}
我一直得到以下输出:
$ gcc -Wall -Wextra -O2 -o realtime realtime.c
$ ./realtime
Sending signal SIRTMIN+1, value 0
Sending signal SIRTMIN+2, value 1
Sending signal SIRTMIN+3, value 2
Sending signal SIRTMIN+1, value 3
Sending signal SIRTMIN+2, value 4
Sending signal SIRTMIN+3, value 5
Sending signal SIRTMIN+3, value 6
Sending signal SIRTMIN+2, value 7
Sending signal SIRTMIN+1, value 8
Sending signal SIRTMIN+3, value 9
Received signal SIGRTMIN+3, value 2
Received signal SIGRTMIN+3, value 5
Received signal SIGRTMIN+3, value 6
Received signal SIGRTMIN+3, value 9
Received signal SIGRTMIN+2, value 1
Received signal SIGRTMIN+2, value 4
Received signal SIGRTMIN+2, value 7
Received signal SIGRTMIN+1, value 0
Received signal SIGRTMIN+1, value 3
Received signal SIGRTMIN+1, value 8
与signal(7)(http://man7.org/linux/man-pages/man7/signal.7.html)中的内容相矛盾:
实时信号以保证的顺序发送。相同类型的多个实时信号按发送顺序传送。如果向进程发送不同的实时信号,则从编号最小的信号开始传送它们。 (即,低编号信号具有最高优先级。)相反,如果一个过程有多个标准信号待处理,则它们的交付顺序是未指定的。
据我了解,我应该得到:
$ ./realtime
Sending signal SIRTMIN+1, value 0
Sending signal SIRTMIN+2, value 1
Sending signal SIRTMIN+3, value 2
Sending signal SIRTMIN+1, value 3
Sending signal SIRTMIN+2, value 4
Sending signal SIRTMIN+3, value 5
Sending signal SIRTMIN+3, value 6
Sending signal SIRTMIN+2, value 7
Sending signal SIRTMIN+1, value 8
Sending signal SIRTMIN+3, value 9
Received signal SIGRTMIN+1, value 0
Received signal SIGRTMIN+1, value 3
Received signal SIGRTMIN+1, value 8
Received signal SIGRTMIN+2, value 1
Received signal SIGRTMIN+2, value 4
Received signal SIGRTMIN+2, value 7
Received signal SIGRTMIN+3, value 2
Received signal SIGRTMIN+3, value 5
Received signal SIGRTMIN+3, value 6
Received signal SIGRTMIN+3, value 9
我已经快速浏览了一下Linux内核源代码,但找不到处理实时信号的地方。
我做错了什么/遗失了什么或者手册页是不准确的?
答案 0 :(得分:6)
您的问题是您允许其他信号中断正在运行的信号处理程序:
sigemptyset(&action.sa_mask);
sa_mask
字段指定不允许中断此处理程序执行的信号集。
这意味着您获得了SIGRTMIN + 1
,然后才能对其进行任何操作您将获得另一个优先级较低的信号,然后您就可以开始处理。然后该信号又被另一个信号中断,依此类推。
要解决此问题,请禁止任何其他信号中断您的处理程序:
sigfillset(&action.sa_mask);
答案 1 :(得分:1)
我认为您的问题就在这一行sigemptyset(&action.sa_mask);
。
以正确的顺序递送信号RT1 - &gt; RT3,但更高优先级信号会在稍后发送时中断优先级较低的信号。
在每个优先级内,信号按发送的顺序传送,默认情况下,传送的信号在发送过程中被阻止,按照发送的顺序正确处理,这会导致您的混合排序。
正如cnicutar所说,切换到使用sigfillset
,一切都会很好。
答案 2 :(得分:0)
上面提到的人问题出在sigemptyset(&action.sa_mask);
行。
所以另一种解决方案是阻止仅发送信号:
::sigaddset(&action.sa_mask, SIGRTMIN + 1);
::sigaddset(&action.sa_mask, SIGRTMIN + 2);
::sigaddset(&action.sa_mask, SIGRTMIN + 3);
P.S:当调用处理程序时,它们自己阻塞信号被认为是一种好习惯。