Как изолировать работу / поток от сбоев - PullRequest
5 голосов
/ 24 августа 2010

Я работаю над библиотекой, в которой я выполняю различные задачи для некоторых сторонних библиотек, которые выполняют относительно скудную или опасную работу для конкретной платформы. (В частности, я пишу синтаксический анализатор математических функций, который вызывает JIT-компиляторы, такие как LLVM или libjit, для создания машинного кода.) На практике эти сторонние библиотеки имеют тенденцию быть сбойным (отчасти это моя ошибка конечно, но мне все еще нужна страховка).

Мне бы хотелось иметь возможность очень изящно справляться с ужасно умирающей работой - SIGSEGV, SIGILL и т. Д. - без сброса остальной части моего кода (или кода пользователей, вызывающих мою библиотеку). функции). Чтобы быть ясным, мне все равно, может ли эта конкретная работа продолжаться (я не собираюсь пытаться исправить состояние сбоя), и при этом я не забочусь о состоянии объектов после такого сбоя (я откажусь их немедленно, если есть крушение). Я просто хочу быть в состоянии обнаружить, что произошел сбой, не дать завершить процесс уничтожения всего процесса, прекратить вызывать любой сбой и возобновить выполнение.

(Для немного большего контекста, код на данный момент представляет собой цикл for, тестирующий каждый из доступных JIT-компиляторов. Некоторые из этих компиляторов могут аварийно завершиться. Если это произойдет, я просто хочу выполнить continue; и получить с тестированием другого компилятора.)

В настоящее время у меня есть реализация на signal(), которая довольно ужасно терпит неудачу; конечно, это неопределенное поведение для longjmp() из обработчика сигнала, и обработчики сигнала, как ожидается, будут заканчиваться exit() или terminate(). Простое добавление кода в другой поток само по себе не помогает, по крайней мере, так, как я его тестировал до сих пор. Я также не могу найти способ заставить эту работу использовать исключения C ++.

Итак, каков наилучший способ изолировать определенный набор инструкций / потока / задания от сбоев?

Ответы [ 4 ]

11 голосов
/ 24 августа 2010

Создать новый процесс.

5 голосов
/ 24 августа 2010

Какой вывод вы получаете при успешном выполнении задания?

Я спрашиваю, потому что, если вывод имеет низкую пропускную способность, у меня возникнет соблазн запустить каждое задание в своем собственном процессе.

Каждый из этихаварийные задания, которые вы запускаете, имеют высокую вероятность повреждения памяти, используемой в других местах вашего процесса.

Процессы обеспечивают наилучшую защиту.

1 голос
/ 24 августа 2010

Процессы обеспечивают наилучшую защиту, но, возможно, вы не сможете этого сделать.

Если точки входа ваших потоков - это написанные вами функции (например, ThreadProc в мире Windows), то вы можете заключить их в блоки try{...}catch(...). Если вы хотите сообщить о том, что произошло исключение, вы можете передать определенные коды ошибок обратно в основной поток или использовать какой-либо другой механизм. Если вы хотите регистрировать не только то, что произошло исключение, но и что это за исключение, вам нужно будет перехватить определенные типы исключений и извлечь из них диагностическую информацию, чтобы связаться с основным потоком. Аля:

int my_tempermental_thread()
{
  try
  {
    // ... magic happens ...
    return 0;
  }
  catch( const std::exception& ex )
  {
    // ... or maybe it doesn't ...
    string reason = ex.what();
    tell_main_thread_what_went_wong(reason);
    return 1;
  }
  catch( ... )
  {
    // ... definitely not magical happenings here ...
    tell_main_thread_what_went_wrong("uh, something bad and undefined");
    return 2;
  }
}

Имейте в виду, что если вы пойдете этим путем, вы рискуете потерять хост-процесс, когда возникают исключения. Вы говорите, что не пытаетесь исправить проблему, но откуда вы знаете, что злокачественная нить не съела ваш стек, например? Лови и игнорируй - отличный способ создавать ужасно запутанные ошибки.

0 голосов
/ 25 августа 2010

В Windows вы можете использовать VirtualProtect(YourMemory, PAGE_READONLY) при вызове ненадежного кода.Любая попытка изменить эту память вызовет структурированное исключение.Вы можете смело ловить это и продолжить выполнение.Тем не менее, память, выделенная этой библиотекой, конечно же, будет течь, как и другие ресурсы.Эквивалент Linux - mprotect(YorMemory, PROT_READ), что вызывает SEGV.

...