Как ограничить время выполнения функции в C/POSIX?

Подобно этому вопросу, я хотел бы ограничить время выполнения функции - предпочтительно с точностью до микросекунды - в Си. Я полагаю, что исключения C++ могут использоваться для достижения результата, аналогичного этому решению Python. Хотя он не идеален, такой подход совершенно недоступен в простой C.

Тогда мне интересно, как я могу прервать выполнение функции через определенный промежуток времени в C в системе Posix? Для относительно простых ситуаций немного глупый бизнес работает просто отлично, но это добавляет изрядное количество кода, ортогонального к решению проблемы. Допустим, у меня есть такая функция:

void boil(egg *e) {
    while (true)
    do_boil(e);
}

Я хочу запустить варить на яйце *, прерывая его каждые 50 мкс, чтобы проверить, что-то вроде этого:

egg *e = init_egg();
while (true) {
    preempt_in(50, (void) (*boil), 1, e);
    /* Now boil(e) is executed for 50μs, 
       then control flow is returned to the
       statement prior to the call to preempt_in.
     */
    if (e->cooked_val > 100)
        break;
}

Я понимаю, что для этого можно использовать pthreads, но я больше заинтересован в том, чтобы избежать их использования. Я мог бы переключаться между ucontext_t в обработчике SIGALRM, но стандарт POSIX отмечает, что использование setcontext/swapcontext не должно использоваться в обработчике сигналов, и, действительно, я отмечаю различное поведение между системами Linux и Solaris при этом.

Можно ли достичь этого эффекта? Если это так, портативным способом?

3 ответа

Решение

Просто отметим, что общие возможности, которые вы ищете здесь, называются принудительным исполнением затрат. Например, см. Эту статью Wellings или Leung, et. отличная книга. Ответы выше направлены на достижение этого в пользовательском пространстве; некоторые RTOS или языки поддерживают его (не linux) как общий механизм.

Одной из примеров ОС, которая обеспечивает это, является ОС AUTOSAR (спецификация связана). Обратите внимание, что эта ОС обеспечивает принудительное выполнение времени выполнения, которое немного отличается от принудительного выполнения. Обеспечение соблюдения времени исполнения становится все сложнее, поскольку оно зависит от некоторой способности измерять фактические затраченные затраты (обычно при взаимодействии с оборудованием). Учитывая сложность современных процессоров, это сложно и дорого измерить - не говоря уже о том, что значение измерений (из-за нелинейного выполнения и всех видов других интересных вещей) трудно интерпретировать - и, следовательно, сложное событие для вычисления (оценка наихудшего или общего) конкретного отрезка времени выполнения кода.

Немного не по теме, но Ada предоставляет здесь более строгий набор возможностей на уровне языка, который вам не поможет, но вы могли бы выяснить, как эти требования Ada были реализованы в Linux. Спецификация языка Ada уникальна в предоставлении обоснованного документа, см. Раздел об упреждающем прерывании в реальном времени в качестве отправной точки.

Вы можете либо использовать потоки, либо сделать так, чтобы функция опрашивала таймер (или глобальную переменную, установленную SIGALRM обработчик), затем сохраните его состояние и выйдите, когда отведенное время истекло. Использование ucontext_t устарела и никогда не должна использоваться в новом коде, тем более от обработчиков сигналов.

Решение, которое я желаю, внезапно приходит ко мне: goto! Я установлю точку перехода сразу после функции, которую я хочу ограничить, установлю таймер и в обработчике сигнала, который имеет дело с SIG*ALRM, просто перейду к инструкции после функции.

Другие вопросы по тегам