我昨天发布了一个类似的问题,但我在概述我的问题方面做得很差,从那时起我认为我已经取得了进展。
我的最小工作示例仍然很长,因此我将发布相关片段,但可以在此处找到完整示例。
我的问题很简单,我有两个 POSIX 消息队列,它们被创建为异步的,并且都由同一个线程上的同一个处理程序处理。我的问题是在一个更基本的层面上,如果一个单独的线程顺序发送到两个队列,那么 sig 处理程序只为第一个队列运行一次。这是有道理的,因为当一个信号调用一个处理程序时,它会自动被阻塞,根据GNU。
因此,当我配置我的时,struct sigaction
我确保从sigset_t
我设置为sa_mask
. 我的假设是,然后使用sigaction(2)SA_NODEFER
中解释的那样,信号处理程序将能够被递归调用(不确定递归是否在这里是正确的词)。
sa_mask 指定在信号处理程序执行期间应被阻塞的信号掩码(即,添加到调用信号处理程序的线程的信号掩码)。此外,触发处理程序的信号将被阻塞,除非使用 SA_NODEFER 标志。
将信号处理程序附加到消息队列的相关代码
assert((conn->fd = mq_open(conn->name, O_CREAT | O_RDONLY | O_NONBLOCK,
0644, &attr)));
/** Setup handler for SIGIO */
/** sigaction(2) specifies that the triggering signal is blocked in the handler */
/** unless SA_NODEFER is specified */
sa.sa_flags = SA_SIGINFO | SA_RESTART | SA_NODEFER;
sa.sa_sigaction = sigHandler;
/** sa_mask specifies signals that will be blocked in the thread the signal */
/** handler executes in */
sigfillset(&sa.sa_mask);
sigdelset(&sa.sa_mask, SIGIO);
if (sigaction(SIGIO, &sa, NULL)) {
printf("Sigaction failed\n");
goto error;
}
printf("Handler set in PID: %d for TID: %d\n", getpid(), gettid());
/** fcntl(2) - FN_SETOWN_EX is used to target SIGIO and SIGURG signals to a */
/** particular thread */
struct f_owner_ex cur_tid = { .type = F_OWNER_TID, .pid = gettid() };
assert(-1 != fcntl(conn->fd, F_SETOWN_EX, &cur_tid));
作为健全性检查,我检查了处理程序内的信号掩码以检查 SIGIO 是否被阻止。
void sigHandler(int signal, siginfo_t *info, void *context)
{
sigset_t sigs;
sigemptyset(&sigs);
pthread_sigmask(0, NULL, &sigs);
if (sigismember(&sigs, SIGIO)) {
printf("SIGIO being blocked in handler\n");
sigaddset(&sigs, SIGIO);
pthread_sigmask(SIG_UNBLOCK, &sigs, NULL);
}
...
}
但是 SIGIO 似乎没有被阻止。我的推理告诉我,鉴于两个消息队列 MQ1 和 MQ2 在 SIGIO 上异步使用相同的处理程序,应该会发生以下情况。考虑到两个线程的时间和信号的延迟,我很难真正知道。最好说我的一些有根据的猜测是:
mq_send
到 MQ1 直接mq_send
从线程 1 到 MQ2- MQ1 的信号处理程序应该在线程 2 上给定来自 MQ1 的 SIGIO 触发
- MQ2 的信号处理程序会在线程 2 上中断 MQ1 的信号处理程序
- MQ2 的信号处理程序在线程 2 上完成
- MQ1 的信号处理程序在线程 2 上完成
运行我之前链接的示例,观察到以下行为
mq_send
到 MQ1 直接mq_send
从线程 1 到 MQ2- MQ1 的信号处理程序触发并完成
这让我觉得 SIGIO 在信号处理程序期间以某种方式被阻止或忽略。鉴于我所读到的内容sa_mask
和我的健全性检查,pthread_sigmask
我不确定为什么我会得到我所看到的行为。我希望我在联机帮助页的某个地方错过了一些小知识。