2011-01-22 3 views
3

Так что мое понимание как pthread_exit, так и pthread_cancel состоит в том, что они оба вызывают исключение, подобное тому, что называется «принудительное раскручивание», выбрасывается из соответствующего стека кадров в целевом потоке. Это можно поймать, чтобы выполнить очистку, зависящую от потока, но ее нужно перебросить, иначе мы получим неявный abort() в конце блока catch, который не был повторно выбрасыван.Неуправляемый принудительный отрыв вызывает отмену

В случае pthread_cancel это происходит либо сразу после получения связанного сигнала, либо следующего входа в точку отмены, либо когда следующий сигнал разблокирован, в зависимости от состояния и типа отмены потока.

В случае pthread_exit, вызывающая нить немедленно подвергается принудительному разматыванию.

Изобразительное. Это «исключение» является нормальной частью процесса уничтожения потока. Итак, почему, даже когда я повторно бросаю его, вызывает ли это вызов std::terminate(), прерывая мое приложение?

Обратите внимание, что я ломаю и повторно бросаю исключение пару раз.

Обратите внимание, что я звоню pthread_exit из моего SIGTERM обработчика сигнала. Это отлично работает в моем тестовом коде игрушек, скомпилированном с g ++ 4.3.2, который имеет поток thread signal(SIGTERM, handler_that_calls_pthread_exit), а затем сидит в тугой петле while, пока не получит сигнал TERM. Но это не работает в реальном приложении.

Соответствующие кадры стека:

(gdb) where 
#0 0x0000003425c30265 in raise() from /lib64/libc.so.6 
#1 0x0000003425c31d10 in abort() from /lib64/libc.so.6 
#2 0x00000000012b7740 in sv_bsd_terminate() at exception_handlers.cpp:38 
#3 0x00002aef65983aa6 in __cxxabiv1::__terminate (handler=0x518) 
    at /view/ken_gcc_4.3/vobs/Compiler/gcc/libstdc++-v3/libsupc++/eh_terminate.cc:43 
#4 0x00002aef65983ad3 in std::terminate() 
    at /view/ken_gcc_4.3/vobs/Compiler/gcc/libstdc++-v3/libsupc++/eh_terminate.cc:53 
#5 0x00002aef65983a5a in __cxxabiv1::__gxx_personality_v0 (
    version=<value optimized out>, actions=<value optimized out>, 
    exception_class=<value optimized out>, ue_header=0x645bcd80, 
    context=0x645bb940) 
    at /view/ken_gcc_4.3/vobs/Compiler/gcc/libstdc++-v3/libsupc++/eh_personality.cc:657 
#6 0x00002aef6524d68c in _Unwind_ForcedUnwind_Phase2 (exc=0x645bcd80, 
    context=0x645bb940) 
    at /view/ken_gcc_4.3/vobs/Compiler/gcc/libgcc/../gcc/unwind.inc:180 
#7 0x00002aef6524d723 in _Unwind_ForcedUnwind (exc=0x645bcd80, 
    stop=<value optimized out>, stop_argument=0x645bc1a0) 
    at /view/ken_gcc_4.3/vobs/Compiler/gcc/libgcc/../gcc/unwind.inc:212 
#8 0x000000342640cf80 in __pthread_unwind() from /lib64/libpthread.so.0 
#9 0x00000034264077a5 in pthread_exit() from /lib64/libpthread.so.0 
#10 0x0000000000f0d959 in threadHandleTerm (sig=<value optimized out>) 
    at osiThreadLauncherLinux.cpp:46 
#11 <signal handler called> 

Спасибо!

Эрик

ответ

4

Заметим также, что я звоню pthread_exit из моего SIGTERM сигнала обработчика.

Это ваша проблема. Цитирую из спецификации POSIX (http://pubs.opengroup.org/onlinepubs/009695399/functions/signal.html):

Если сигнал происходит иначе, чем в результате вызова прерывания(), поднять(), kill(), pthread_kill() или sigqueue(), , поведение не определено, если обработчик сигнала ссылается на любой объект со статической продолжительностью хранения, отличным от назначения значения объекту, объявленному как volatile sig_atomic_t, или если обработчик сигнала вызывает любую функцию в стандартной библиотеке, отличную от одной из функций, перечисленных в концепциях сигналов.

Список разрешенных функций приведен в http://pubs.opengroup.org/onlinepubs/009695399/functions/xsh_chap02_04.html#tag_02_04_03, и не включает в себя pthread_exit(). Поэтому ваша программа демонстрирует неопределенное поведение.

я могу думать о трех вариантов:

  1. Установите флаг в обработчике, который проверяется в потоке периодически, а не пытаться выйти непосредственно из обработчика сигнала.
  2. Используйте sigwait(), чтобы явно ждать сигнала на независимой нити. Затем этот поток может явным образом вызвать pthread_cancel() в потоке, который вы хотите закрыть.
  3. Маскируйте сигнал и периодически вызывайте sigpending() в поток, который должен быть выведен, и выйдите, если сигнал находится в ожидании.