Отмена темы, которая застряла на epoll_wait

Я делаю некоторую обработку событий с C ++ и pthreads. У меня есть основной поток, который читает из определенной мной очереди событий, и рабочий поток, который заполняет очередь событий. Очередь, конечно, потокобезопасна.

Рабочий поток имеет список файловых дескрипторов и создает системный вызов epoll для получения событий этих файловых дескрипторов. Он использует epoll_wait для ожидания событий на fd.

Теперь проблема. Предполагая, что я хочу правильно завершить свое приложение, как я могу правильно отменить рабочий поток? epoll_wait не является одной из точек отмены нитей (7) поэтому он не может правильно реагировать на pthread_cancel,

Рабочий поток main () выглядит так

while(m_WorkerRunning) {
epoll_wait(m_EpollDescriptor, events, MAXEVENTS, -1);
//handle events and insert to queue
}

m_WorkerRunning установлен в true когда нить начинается и похоже, что я Можно прервать поток по настройкам m_WorkerRunning ложь из основного потока. Проблема в том, что epoll_wait теоретически можно ждать вечно.

Другое решение, о котором я думаю: вместо того, чтобы ждать вечно (-1), я могу ждать, например, X временных интервалов, затем правильно обрабатывать случай отсутствия событий, и если m_WorkerRunning == false затем выйдите из цикла и полностью завершите рабочий поток. Затем основной поток устанавливает m_WorkerRunning ложно, и спит X. Однако я не уверен в производительности такого epoll_wait, а также не уверен, что будет правильным X? 500мс? 1s? 10s?

Я хотел бы услышать некоторые опытные советы!

Более актуальная информация: события, на которых я жду /dev/input так что технически я делаю какую-то подсистему ввода. Целевая ОС — Linux (последнее ядро) на архитектуре ARM.

Спасибо!

3

Решение

Вы можете отправить потоку сигнал, который прервет блокирующий вызов epoll_wait(), Если это так, измените ваш код следующим образом:

while(m_WorkerRunning)
{
int result = epoll_wait(m_EpollDescriptor, events, MAXEVENTS, -1);
if (-1 == result)
{
if (EINTR == errno)
{
/* Handle shutdown request here. */
break;
}
else
{
/* Error handling goes here. */
}
}

/* Handle events and insert to queue. */
}

Способ добавить обработчик сигнала:

#include <signal.h>

/* A generic signal handler doing nothing */
void signal_handler(int sig)
{
sig = sig; /* Cheat compiler to not give a warning about an unused variable. */
}

/* Wrapper to set a signal handler */
int signal_handler_set(int sig, void (*sa_handler)(int))
{
struct sigaction sa = {0};
sa.sa_handler = sa_handler;
return sigaction(sig, &sa, NULL);
}

Чтобы установить этот обработчик для сигнала SIGUSR1 делать:

if (-1 == signal_handler_set(SIGUSR1, signal_handler))
{
perror("signal_handler_set() failed");
}

Отправить сигнал SIGUSR1 из другого процесса:

if (-1 == kill(<target process' pid>, SIGUSR1))
{
perror("kill() failed");
}

Чтобы процесс отправил сигнал самому себе:

if (-1 == raise(SIGUSR1))
{
perror("raise() failed");
}
2

Другие решения

ответ алка выше почти правильный. Разница, однако, очень опасна.

Если вы собираетесь отправить сигнал, чтобы проснуться epoll_wait, никогда используйте epoll_wait. Вы должны использовать epoll_pwaitили вы можете столкнуться с гонкой, когда ваш эполл никогда не проснется.

Сигналы поступают асинхронно. Если твой SIGUSR1 прибывает после того, как вы проверили свою процедуру выключения, но прежде чем ваш цикл возвращается к epoll_wait, тогда сигнал не прервет ожидание (так как его нет), но и программа не выйдет.

Это может быть очень вероятным или крайне маловероятным, в зависимости от того, сколько времени занимает цикл в зависимости от того, сколько времени потрачено на ожидание, но это ошибка, так или иначе.

Другая проблема с ответом алка в том, что он не проверяет Зачем ожидание было прервано. Причин может быть несколько, не связанных с вашим выходом.

Для получения дополнительной информации см. Справочную страницу для pselect. epoll_pwait работает аналогичным образом.

Кроме того, никогда не отправляйте сигналы потокам, используя kill, использование pthread_kill вместо. killПоведение при отправке сигналов в лучшем случае не определено. Нет гарантии, что правильный поток получит его, что может привести к прерыванию несвязанного системного вызова или к тому, что ничего не произойдет.

6

По вопросам рекламы [email protected]