【发布时间】:2020-05-04 11:44:23
【问题描述】:
我昨天发布了一个类似的question,但我在概述我的问题方面做得很差,从那以后我认为我已经取得了进展。
我的最小工作示例仍然很长,因此我将发布相关的 sn-ps,但可以在 here 找到完整示例。
我的问题很简单,我有两个 POSIX 消息队列,它们被创建为异步的,并且都由同一个线程上的同一个处理程序处理。我的问题是在一个更基本的层面上,如果一个单独的线程按顺序发送到两个队列,那么 sig 处理程序只为第一个队列运行一次。根据GNU,这是有道理的,因为当信号调用处理程序时,它会自动被阻塞。
因此,当我配置我的struct sigaction 时,我确保从我设置为sa_mask 的sigset_t 中删除目标信号(SIGIO)。我的假设是,然后使用SA_NODEFER,如sigaction(2) 中所述,信号处理程序将能够被递归调用(不确定递归是否是正确的词)。
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 进行的健全性检查,我不确定为什么会出现我所看到的行为。我希望我在手册页的某个地方漏掉了一些小知识。
【问题讨论】:
-
您的代码在信号处理程序中调用非异步安全函数时表现出未定义的行为。
标签: c pthreads signals posix sigaction