Когда стоит использовать epoll_pwait и для чего?
Не могу понять смысл вызова epoll_pwait. Сказано, что он является потокобезопасным, но, насколько я знаю, epoll_wait тоже можно использовать в многопоточной среде, ошибок не должно возникать, синхронизация происходит в ядре.
В каких ситуациях использования epoll_pwait необходимо?
Ответы (1 шт):
Если присмотрется в манах на отличия этих двух функций, то видно, что epoll_pwait имеет один дополнительный аргумент. Там же приводится объяснение отличий. Я чуточку доработал пример с мана. По факту, функция epoll_pwait выглядит вот так, только ядро обещает, что это будет выполнено атомарно (читайте, что тело функции завернуто в мютекс)
int epoll_pwait(int epfd, struct epoll_event *events,
int maxevents, int timeout,
const sigset_t *sigmask)
{
// mutex-lock-here
sigset_t origmask;
sigprocmask(SIG_SETMASK, &sigmask, &origmask);
ready = epoll_wait(epfd, events, maxevents, timeout);
sigprocmask(SIG_SETMASK, &origmask, NULL);
// mutex-unlock-here
}
то есть, можно выставить нужную маску на сигналы, вызвать функцию и подождать, а потом вернуть назад.
Но возникает вопрос, а зачем? тут все хитро. Очень часто хочется обрабатывать сигналы (те, которые sigusr/sigkill и другие). И тут есть две стратегии - в одном случае вся обработка идет прямо в обработчике. Но, не смотря на простоту такого метода, у него есть куча ограничений. Даже если захочется "перезагрузить конфиг" по sigusr, то в обычном обработчике это сложно сделать правильно и корректно. Обработчик может прервать основной код в "произвольном месте".
И есть второй способ - обработчик сигнала делает ровно одну штуку - выставляет специальный флаг. А функция poll/epoll/select и многие другие умеют по сигналу прерывать свою работу с возвратом соответствующего кода. И основной код, получив такой код возврата может проверить флажки и корректно сделать свою работу. И все становится достаточно просто. Но есть некоторые ситуации, когда сигнал может прийти между проверкой флажка и вызовом poll/select/epoll. И с одной стороны экстренная ситуация произошла, а ее не проверили, а select/poll/epoll могут повиснуть надолго (навсегда). Об этом можно почитать в описании pselect который имеет подобную задачу.
А с этим вызовом ситуация меняется. Сигнал может прийти только тогда, когда мы ожидаем в epoll_pwait. А в остальное время он замаскирован. Получается такой себе мютекс на данные.