2010-08-24 2 views
5

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

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

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

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

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

ответ

10

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

+1

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

+0

Спасибо за хед-ап. Почти наверняка правильный ответ здесь. Я прочь читать на fork() и компании. –

5

Какой результат вы собираете, когда работа преуспевает?

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

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

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

1

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

Если точки входа ваших потоков - это функции, которые вы написали (например, 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; 
    } 
} 

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

0

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

Смежные вопросы