Я вчера опубликовал похожий вопрос , но я плохо описал свою проблему, и с тех пор я думаю, что добился прогресса.
Мой минимальный рабочий пример все еще довольно длинный, поэтому Я опубликую соответствующие фрагменты, но полный пример можно найти здесь .
Моя проблема довольно проста, у меня есть две очереди сообщений POSIX, которые созданы асинхронными и обе обрабатываются тот же обработчик в том же потоке. Моя проблема на более фундаментальном уровне в том, что если отдельный поток отправляет в обе очереди последовательно, то обработчик sig запускается только один раз для первой очереди. Это имеет смысл, учитывая, что когда сигнал вызывает обработчик, он автоматически блокируется в соответствии с GNU .
Поэтому при настройке struct sigaction
я убрал целевой сигнал (SIGIO) из sigset_t
, который я установил как sa_mask
. Я предполагал, что затем, используя 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, которые asyn c используют один и тот же обработчик на SIGIO. Учитывая временную привязку двух потоков и задержку сигналов, мне трудно понять. Лучше сказал бы, что мое кое-что образованное предположение будет:
mq_send
до MQ1, за которым сразу следует mq_send
до MQ2 из потока 1 - Обработчик сигнала MQ1 должен сработать, учитывая SIGIO из MQ1 в потоке 2
- Обработчик сигнала MQ2 прервет обработчик сигнала MQ1 в потоке 2
- Обработчик сигнала MQ2 завершится в потоке 2
- Обработчик сигнала MQ1 завершится в потоке 2
При выполнении примера, который я связал ранее, наблюдается следующее поведение
mq_send
для MQ1, за которым следуют mq_send
для MQ2 из потока 1 - MQ1 обработчик сигнала запускается и завершается
, что заставляет меня думать, что SIGIO каким-то образом блокируется или игнорируется во время обработки сигнала. Учитывая то, что я прочитал о sa_mask
и о моей проверке работоспособности с использованием pthread_sigmask
, я не уверен, почему у меня такое поведение, которое я вижу. Я надеюсь, что пропустил какой-то маленький кусочек знания где-то на страницах руководства.