Процесс прерывается с помощью SIGABRT, когда поток запускается после того, как исключение было перехвачено в другом потоке.

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

Ниже приведен код потока обработчика выхода.

void Class::TaskExitHandler::run() throw()
{

while( ! isInterrupted() ) {

    _book->_eot_cond.wait(); // Waiting on this condition
    {
        CLASS_NAMESPACE::Guard<CLASS_NAMESPACE::FastLock> eguard(_book->_exitlist_lock);

        list<TaskGroupExecutor*>::const_iterator itr = _book->_exited_tasks.begin();

        for( ; itr != _book->_exited_tasks.end(); itr++ ) {
            (*itr)->join();
            TRACER(TRC_DEBUG)<< "Deleting exited task:" << (*itr)->getLoc() << ":"
                     << (*itr)->getTestID() << ":" << (*itr)->getReportName() << endl;
            delete (*itr);
        }
        _book->_exited_tasks.clear();
    }
    _book->executeAny();
}
}
}

Теперь было замечено, что когда рабочий поток перехватывает любое исключение (поднятое с нижнего уровня), этот поток продолжается и немедленно запускает ядро ​​с кодом выхода 134, то есть SIGABRT.

Трассировка стека выглядит следующим образом:

#0  0x0000005555f49b4c in raise () from /lib64/libc.so.6
#1  0x0000005555f4b568 in abort () from /lib64/libc.so.6
#2  0x0000005555d848b4 in __gnu_cxx::__verbose_terminate_handler () from /usr/lib64/libstdc++.so.6
#3  0x0000005555d82210 in ?? () from /usr/lib64/libstdc++.so.6
#4  0x0000005555d82258 in std::terminate () from /usr/lib64/libstdc++.so.6
#5  0x0000005555d82278 in ?? () from /usr/lib64/libstdc++.so.6
#6  0x0000005555d81b18 in __cxa_call_unexpected () from /usr/lib64/libstdc++.so.6
#7  0x0000000120047898 in Class::TaskExitHandler::run ()
#8  0x000000012001cd38 in commutil::ThreadBase::thread_proxy ()
#9  0x0000005555c6e438 in start_thread () from /lib64/libpthread.so.0
#10 0x0000005555feed6c in __thread_start () from /lib64/libc.so.6
Backtrace stopped: frame did not save the PC

Таким образом, кажется, что эта функция run(), которая указывает, что она не будет генерировать никаких исключений, используя спецификацию «throw()», вызывает исключение (из кадра 4). Согласно различным ссылкам на __cxa_call_unexpected(), трассировка стека отображает типичное поведение компилятора для прерывания, когда в функции со спецификацией «throw()» возникает исключение. Я прав с анализом проблемы?

Для проверки я добавил в этот метод функцию try catch и напечатал сообщение об исключении. Теперь процесс не запустился. Сообщение об исключении было таким же, как и сообщение, перехваченное рабочим потоком. Мой вопрос: как этот поток получает доступ к исключению, пойманному другим? Имеют ли они общую структуру данных, связанную с обработкой исключений?

Пожалуйста, пролейте свет на это. Это довольно озадачивает..

Примечание. В соответствии с трассировкой стека call_unexpected возникает сразу после вызова run(). Это усиливает мои сомнения в том, что стек исключений или данные каким-то образом являются общими. Но не нашел никаких ссылок на это поведение.


person Vivek    schedule 27.04.2012    source источник
comment
«Похоже, что эта функция run(), которая указывает, что она не будет генерировать никаких исключений, используя спецификацию throw(), вызывает исключение (из кадра 4)» Хех! Если вы хотите, чтобы работа была сделана должным образом, сначала сожгите все спецификации!   -  person Martin James    schedule 27.04.2012
comment
Ага! к сожалению, этот класс должен наследовать от общего служебного класса, и, следовательно, ограничение. :(   -  person Vivek    schedule 27.04.2012
comment
Может обе темы закинули? Это странный код - он выглядит почти как микроуправление потоками.   -  person Martin James    schedule 27.04.2012
comment
Я представил try-catch, чтобы проверить, был ли запущен поток обработчика выхода. Оказалось, что это то же самое сообщение, которое получит рабочий обработчик. Кроме того, он не вызывается ни одним из вызываемых здесь методов, иначе он был бы виден в трассировке стека.   -  person Vivek    schedule 27.04.2012
comment
Хм. Я просто думаю. оба этих потока унаследованы от общего класса, который является синглтоном и так далее. Есть ли шанс, что этот класс поддерживает свой стек как статические данные, чтобы все унаследованные классы и их объекты видели одни и те же исключения? Я просто спрашиваю, возможно ли это таким образом. Если да, то я могу покопаться в этом коде...   -  person Vivek    schedule 27.04.2012
comment
Да, по этой причине я уже обесценил getLoc() и т. д. Это похоже на какую-то двойную ошибку, когда рабочий поток исключает, пытается уничтожить себя и снова исключается в dtor после сигнала condvar. Что это сделает с потоком, пытающимся дождаться соединения(), я не знаю.. :((   -  person Martin James    schedule 27.04.2012
comment
первопричина выявлена. оказалось, что в деструкторе объекта, на который указывает *itr, выполняется та же операция и снова выбрасывается такое же исключение. в любом случае попытка-улов держится :) на вопрос дан ответ .. как мне закрыть это ??   -  person Vivek    schedule 30.04.2012
comment
Хороший вопрос. Может быть, вы могли бы опубликовать ответ на свой вопрос?   -  person Martin James    schedule 30.04.2012


Ответы (2)


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

Поскольку поток TaskExitHandler был спроектирован так, чтобы не вызывать (или, скорее, ожидать), не было блоков try-catch, и, следовательно, процесс прерывался при возникновении исключения.

Поскольку вызов деструктора был неявным, он никогда не отображался в трассировке стека, что очень затрудняло его поиск. Каждый объект должен был быть отслежен, чтобы найти эту утечку исключения.

Спасибо всем за активное участие :) это был мой первый вопрос, на который были получены активные ответы..

person Vivek    schedule 03.05.2012

Я рискну — надеюсь, этого будет достаточно, чтобы вы продолжили свои исследования.

Я подозреваю, что поток, выполняющий TaskExitHandler, является родительским потоком для всех рабочих потоков. В противном случае TEH было бы трудно воссоединиться с детьми.

Дочерние/рабочие потоки не обрабатывают выброшенные им исключения. Однако исключение должно быть обработано где-то, иначе весь процесс будет остановлен. Родительский поток (также известный как TEH) является последней остановкой в ​​стеке/цепочке процесса для обработки исключений. Ваш пример кода показывает, что обработка исключений TEH заключается в том, чтобы просто генерировать/не обрабатывать исключение. Так что это ядро.

Это не обязательно общая структура данных, а скорее идентификаторы процессов/потоков и пространство памяти. Дочерние потоки разделяют глобальную память/пространство кучи с родительским и друг с другом, следовательно, необходимы семафоры и/или мьютексы для целей блокировки.

Хорошая инкапсуляция требует, чтобы рабочие потоки были достаточно умными, чтобы обрабатывать любые/все исключения, которые они могут увидеть. Таким образом, отдельный рабочий поток может быть уничтожен вместо того, чтобы останавливать родительский поток и остальную часть дерева процессов. OTW, вы можете продолжать перехватывать исключения в TEH, но маловероятно, что поток знает (или должен знать), что делать с исключением.

Добавьте комментарий, если вышеизложенное не ясно, я буду рад объяснить дальше.

Я провел небольшое исследование и подтвердил, что исключения генерируются для памяти кучи, а не памяти стека. Все потоки вашего процесса используют одну и ту же кучу *, поэтому более понятно (по крайней мере, для меня), почему родительский поток увидит исключение, когда дочерний поток его не поймает. *FWIW, если вы разветвите свой процесс вместо запуска нового потока, вы также получите новую кучу. Однако разветвление — это дорогостоящая операция с памятью, поскольку вы также копируете все содержимое кучи в новый процесс.

В этом потоке SO обсуждается настройка потока для перехвата всех исключений, что, вероятно, будет представлять интерес: из другой темы

person Community    schedule 01.05.2012
comment
ваше объяснение имеет смысл. но здесь это не так. Я определил ответ на свою проблему. вы можете увидеть мои комментарии выше для ответа. Но я хотел бы знать, что если один поток выдает исключение, может ли его поймать другой поток (не родительский, а родственный)? Я не публикую новый вопрос. Первоначальный вопрос, связанный с проблемой, был таким же. Проблема решена, но ответа на мой вопрос нет :) - person Vivek; 03.05.2012