Я думаю, что это недостаток реализации в реализации glibc таймеров POSIX. Конечно, функция timer_getoverrun
, которая критична для использования в реальном времени, не может работать в реализации glibc, так как она возвращает ядру счет переполнения для «текущего» истечения, но когда несколько событий истечения выполняются параллельно «текущий» не имеет смысла. Существуют также серьезные проблемы с истощением ресурсов и событиями истечения срока действия, которые делают реализацию непригодной для целей реального времени. Например, в nptl/sysdeps/unix/sysv/linux/timer_routines.c
:
struct thread_start_data *td = malloc (sizeof (*td));
/* There is not much we can do if the allocation fails. */
...
На справочной странице Linux для sigevent
вы видите для SIGEV_THREAD
:
К числу возможных вариантов реализации относится то, что каждое уведомление о таймере может привести к созданию нового потока или что один поток создается для получения всех уведомлений.
Последнее является единственным выбором, который может обеспечить правильную семантику в реальном времени, но по какой-то причине glibc не принял этот выбор.
Вот возможный обходной путь:
Выберите сигнал в реальном времени, заблокируйте этот сигнал перед созданием каких-либо потоков и настройте таймер на использование этого сигнала с SIGEV_SIGNAL
. Теперь создайте поток для обработки вашего таймера (ов) и выполните цикл по sigwaitinfo
, а затем вызывайте функцию-обработчик каждый раз, когда он возвращается. На самом деле это одна из возможных реализаций (и наиболее правильная) SIGEV_THREAD
, которую должен использовать glibc .
Другая возможность: в POSIX есть ровно одна связанная с синхронизацией, не вызывающая syscall, безопасная асинхронно-сигнальная функция: sem_post
. Таким образом, может быть возможно заставить обработчик сигнала (в отличие от получения сигнала от sigwaitinfo
) синхронизироваться с другим потоком с целью доставки событий таймера. Но я не проработал детали, и кажется, что это все еще может быть трудно или невозможно.