C++ Rest SDK Касабланка Сигтрап
Я использую C++ Rest SDK ("Касабланка") для получения фида с Websocket-серверов. В настоящее время у меня есть три разных подключения к трем различным серверам, работающим одновременно с использованием класса websocket_callback_client.
Программа работает в течение неопределенного времени, а затем неожиданно получает SIGTRAP, Trace/ Breakpoint trap
, Это вывод GDB
:
#0 0x00007ffff5abec37 in __GI_raise (sig=5) at ../nptl/sysdeps/unix/sysv/linux/raise.c:56
#1 0x000000000047bb8e in pplx::details::_ExceptionHolder::~_ExceptionHolder() ()
#2 0x000000000044be29 in std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release() ()
#3 0x000000000047fa39 in pplx::details::_Task_impl<unsigned char>::~_Task_impl() ()
#4 0x000000000044be29 in std::_Sp_counted_base<(__gnu_cxx::_Lock_policy)2>::_M_release() ()
#5 0x00007ffff6feb09f in std::__shared_count<(__gnu_cxx::_Lock_policy)2>::~__shared_count (this=0x7fffc8021420, __in_chrg=<optimized out>) at /usr/include/c++/4.8/bits/shared_ptr_base.h:546
#6 0x00007ffff6fffa38 in std::__shared_ptr<pplx::details::_Task_impl<unsigned char>, (__gnu_cxx::_Lock_policy)2>::~__shared_ptr (this=0x7fffc8021418, __in_chrg=<optimized out>) at /usr/include/c++/4.8/bits/shared_ptr_base.h:781
#7 0x00007ffff6fffa52 in std::shared_ptr<pplx::details::_Task_impl<unsigned char> >::~shared_ptr (this=0x7fffc8021418, __in_chrg=<optimized out>) at /usr/include/c++/4.8/bits/shared_ptr.h:93
#8 0x00007ffff710f766 in pplx::details::_PPLTaskHandle<unsigned char, pplx::task<unsigned char>::_InitialTaskHandle<void, void web::websockets::client::details::wspp_callback_client::shutdown_wspp_impl<websocketpp::config::asio_tls_client>(std::weak_ptr<void> const&, bool)::{lambda()#1}, pplx::details::_TypeSelectorNoAsync>, pplx::details::_TaskProcHandle>::~_PPLTaskHandle() (this=0x7fffc8021410, __in_chrg=<optimized out>)
at /home/cpprestsdk/Release/include/pplx/pplxtasks.h:1631
#9 0x00007ffff716e6f2 in pplx::task<unsigned char>::_InitialTaskHandle<void, void web::websockets::client::details::wspp_callback_client::shutdown_wspp_impl<websocketpp::config::asio_tls_client>(std::weak_ptr<void> const&, bool)::{lambda()#1}, pplx::details::_TypeSelectorNoAsync>::~_InitialTaskHandle() (this=0x7fffc8021410, __in_chrg=<optimized out>) at /home/cpprestsdk/Release/include/pplx/pplxtasks.h:3710
#10 0x00007ffff716e722 in pplx::task<unsigned char>::_InitialTaskHandle<void, void web::websockets::client::details::wspp_callback_client::shutdown_wspp_impl<websocketpp::config::asio_tls_client>(std::weak_ptr<void> const&, bool)::{lambda()#1}, pplx::details::_TypeSelectorNoAsync>::~_InitialTaskHandle() (this=0x7fffc8021410, __in_chrg=<optimized out>) at /home/cpprestsdk/Release/include/pplx/pplxtasks.h:3710
#11 0x00007ffff71f9cdd in boost::_bi::list1<boost::_bi::value<void*> >::operator()<void (*)(void*), boost::_bi::list0> (this=0x7fffdc7d7d28, f=@0x7fffdc7d7d20: 0x479180 <pplx::details::_TaskProcHandle::_RunChoreBridge(void*)>, a=...)
at /usr/local/include/boost/bind/bind.hpp:259
#12 0x00007ffff71f9c8f in boost::_bi::bind_t<void, void (*)(void*), boost::_bi::list1<boost::_bi::value<void*> > >::operator() (this=0x7fffdc7d7d20) at /usr/local/include/boost/bind/bind.hpp:1222
#13 0x00007ffff71f9c54 in boost::asio::asio_handler_invoke<boost::_bi::bind_t<void, void (*)(void*), boost::_bi::list1<boost::_bi::value<void*> > > > (function=...) at /usr/local/include/boost/asio/handler_invoke_hook.hpp:69
#14 0x00007ffff71f9bea in boost_asio_handler_invoke_helpers::invoke<boost::_bi::bind_t<void, void (*)(void*), boost::_bi::list1<boost::_bi::value<void*> > >, boost::_bi::bind_t<void, void (*)(void*), boost::_bi::list1<boost::_bi::value<void*> > > > (function=..., context=...) at /usr/local/include/boost/asio/detail/handler_invoke_helpers.hpp:37
#15 0x00007ffff71f9b2e in boost::asio::detail::completion_handler<boost::_bi::bind_t<void, void (*)(void*), boost::_bi::list1<boost::_bi::value<void*> > > >::do_complete (owner=0x7488d0, base=0x7fffc801ecd0)
at /usr/local/include/boost/asio/detail/completion_handler.hpp:68
#16 0x00000000004c34c1 in boost::asio::detail::task_io_service::run(boost::system::error_code&) ()
#17 0x00007ffff709fb27 in boost::asio::io_service::run (this=0x7ffff759ab78 <crossplat::threadpool::shared_instance()::s_shared+24>) at /usr/local/include/boost/asio/impl/io_service.ipp:59
#18 0x00007ffff7185a81 in crossplat::threadpool::thread_start (arg=0x7ffff759ab60 <crossplat::threadpool::shared_instance()::s_shared>) at /home/cpprestsdk/Release/include/pplx/threadpool.h:133
#19 0x00007ffff566e184 in start_thread (arg=0x7fffdc7d8700) at pthread_create.c:312
#20 0x00007ffff5b8237d in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:111
В строке #18 указывается сообщение /pplx/threadpool.h:133. Это исходный код вокруг этих строк:
123 static void* thread_start(void *arg)
124 {
125 #if (defined(ANDROID) || defined(__ANDROID__))
126 // Calling get_jvm_env() here forces the thread to be attached.
127 get_jvm_env();
128 pthread_cleanup_push(detach_from_java, nullptr);
129 #endif
130 threadpool* _this = reinterpret_cast<threadpool*>(arg);
131 try
132 {
133 _this->m_service.run();
134 }
135 catch (const _cancel_thread&)
136 {
137 // thread was cancelled
138 }
139 catch (...)
140 {
141 // Something bad happened
142 #if (defined(ANDROID) || defined(__ANDROID__))
143 // Reach into the depths of the 'droid!
144 // NOTE: Uses internals of the bionic library
145 // Written against android ndk r9d, 7/26/2014
146 __pthread_cleanup_pop(&__cleanup, true);
147 throw;
148 #endif
149 }
150 #if (defined(ANDROID) || defined(__ANDROID__))
151 pthread_cleanup_pop(true);
152 #endif
153 return arg;
154 }
В целях разъяснения, m_service
это boost::asio::io_service
, Мне кажется, что строка #133 создает исключение, она попадает в строку #139 и затем перебрасывается. На данный момент, я должен поймать это лично, потому что если я не и pplx
-объект уничтожается с неисследованным исключением, он поднимает SIGTRAP
,
Вот как далеко я продвинулся в своем исследовании. Проблема в том, что я понятия не имею, где это происходит. Я окружил каждую позицию, где данные отправлены или получены от websocket_callback_client
с try {} catch(...){}
и это все еще происходит.
Может быть, кто-то, кто использовал эту библиотеку раньше, может мне помочь.
2 ответа
По моему опыту это происходит из-за отдельной проблемы.
Когда вызывается обработчик закрытия websocket_callback_client, большинство людей пытаются удалить websocket_callback_client. Это внутренне вызывает функцию закрытия.
Когда это произойдет, websocket_callback_client будет ждать окончания закрытия. Если другой поток обнаружит, что соединение разорвано и попытается очистить, у вас будет один и тот же объект, который будет удален из двух разных мест, что вызовет серьезные проблемы.
Как повторно подключиться к серверу, который не отвечает на close(), достаточно подробно рассмотрено, что происходит, когда cpprestsdk вызывает close.
Надеюсь это поможет:)
Редактировать: Как выясняется (ответ, который я дал в связанном вопросе, имеет это), если вы попытаетесь закрыть или удалить websocket_callback_client из обработчика закрытия, он сам вызовет обработчик закрытия, который заблокирует поток.
Решение, которое я нашел, которое работает лучше всего для меня, это установить флаг в обработчике закрытия и выполнить очистку в основном потоке или, по крайней мере, в альтернативном потоке.
Пересматривая это. Я нашел обходной путь, который я разместил на cpprestsdk github ( https://github.com/Microsoft/cpprestsdk/issues/427).
SDK плохо справляется с выявлением исключений, и в проблеме, которую я указал, им нужно улучшить документацию по этому вопросу, а также предоставить чистый публичный интерфейс для этого (вы увидите, что решение имеет запах кода),
Что нужно сделать, это сбросить пользовательское исключение.
Это в контексте создания http_client
запрос вызова, но должен быть применим для любого использования pplx.
client->request(request).then([=] (web::http::http_response response) mutable {
// Your code here
}).then([=] (pplx::task<void> previous_task) mutable {
if (previous_task._GetImpl()->_HasUserException()) {
auto holder = previous_task._GetImpl()->_GetExceptionHolder(); // Probably should put in try
try {
// Need to make sure you try/catch here, as _RethrowUserException can throw
holder->_RethrowUserException();
} catch (std::exception& e) {
// Do what you need to do here
}
}
});
Обработка для обнаружения этого "ненаблюдаемого исключения" выполняется во втором then()
,