ZLToolKit icon indicating copy to clipboard operation
ZLToolKit copied to clipboard

增加 releasePool 使得外部可以主动释放Pollers

Open jeyawn opened this issue 1 month ago • 2 comments

问题背景:

https://github.com/ZLMediaKit/ZLMediaKit/issues/4580

更新代码到commit:8c9439571032a0db7d678a0104443125dc0d6916,在windows平台,编译Release版本的ZLMediaKit,并且勾选编译产物是动态库,然后启动MediaServer,之后按Ctrl+c 退出的时候,程序将无法正常退出,查看堆栈如下: ntdll.dll!00007ff827e94a34() 未知 ZLToolKit.dll!reflock__await_event(void * address) 行 1382 C ZLToolKit.dll!reflock_unref_and_destroy(reflock * reflock) 行 1415 C ZLToolKit.dll!ts_tree_node_unref_and_destroy(ts_tree_node * node) 行 1786 C ZLToolKit.dll!epoll_close(void * ephnd) 行 513 C

ZLToolKit.dll!toolkit::EventPoller::~EventPoller() 行 113 C++ ZLToolKit.dll!toolkit::EventPoller::scalar deleting destructor'(unsigned int) C++ ZLToolKit.dll!std::_Ref_counttoolkit::EventPoller::_Destroy() 行 1205 C++ ZLToolKit.dll!std::_Ref_count_base::_Decref() 行 1179 C++ ZLToolKit.dll!std::_Ptr_basetoolkit::TaskExecutor::_Decref() 行 1405 C++ ZLToolKit.dll!std::shared_ptrtoolkit::TaskExecutor::~shared_ptrtoolkit::TaskExecutor() 行 1688 C++ ZLToolKit.dll!std::shared_ptrtoolkit::TaskExecutor::scalar deleting destructor'(unsigned int) C++ ZLToolKit.dll!std::_Default_allocator_traits<std::allocatorstd::shared_ptrtoolkit::TaskExecutor>::destroystd::shared_ptrtoolkit::TaskExecutor(std::allocatorstd::shared_ptrtoolkit::TaskExecutor & __formal, std::shared_ptrtoolkit::TaskExecutor * const _Ptr) 行 730 C++ ZLToolKit.dll!std::_Destroy_range<std::allocatorstd::shared_ptrtoolkit::TaskExecutor>(std::shared_ptrtoolkit::TaskExecutor * _First, std::shared_ptrtoolkit::TaskExecutor * const Last, std::allocatorstd::shared_ptrtoolkit::TaskExecutor & Al) 行 1088 C++ ZLToolKit.dll!std::vector<std::shared_ptrtoolkit::TaskExecutor,std::allocatorstd::shared_ptrtoolkit::TaskExecutor>::Tidy() 行 2047 C++ ZLToolKit.dll!std::vector<std::shared_ptrtoolkit::TaskExecutor,std::allocatorstd::shared_ptrtoolkit::TaskExecutor>::~vector<std::shared_ptrtoolkit::TaskExecutor,std::allocatorstd::shared_ptrtoolkit::TaskExecutor>() 行 769 C++ ZLToolKit.dll!toolkit::TaskExecutorGetterImp::~TaskExecutorGetterImp() 行 262 C++ ZLToolKit.dll!toolkit::EventPollerPool::~EventPollerPool() 行 350 C++ ZLToolKit.dll!toolkit::EventPollerPool::scalar deleting destructor'(unsigned int) C++ ZLToolKit.dll!std::_Ref_counttoolkit::EventPollerPool::_Destroy() 行 1205 C++ ZLToolKit.dll!std::_Ref_count_base::_Decref() 行 1179 C++ ZLToolKit.dll!std::_Ptr_basetoolkit::EventPollerPool::_Decref() 行 1405 C++ ZLToolKit.dll!std::shared_ptrtoolkit::EventPollerPool::~shared_ptrtoolkit::EventPollerPool() 行 1688 C++ ZLToolKit.dll!toolkit::EventPollerPool::Instance'::2'::dynamic atexit destructor for 's_instance''() C++ ucrtbased.dll!00007fffa1442c21() 未知 ucrtbased.dll!00007fffa14423f5() 未知 ucrtbased.dll!00007fffa1442547() 未知 ucrtbased.dll!00007fffa1442e34() 未知 ZLToolKit.dll!scrt_dllmain_uninitialize_c() 行 399 C++ ZLToolKit.dll!dllmain_crt_process_detach(const bool is_terminating) 行 182 C++ ZLToolKit.dll!dllmain_crt_dispatch(HINSTANCE * const instance, const unsigned long reason, void * const reserved) 行 220 C++ ZLToolKit.dll!dllmain_dispatch(HINSTANCE * const instance, const unsigned long reason, void * const reserved) 行 293 C++ ZLToolKit.dll!DllMainCRTStartup(HINSTANCE * const instance, const unsigned long reason, void * const reserved) 行 335 C++ ntdll.dll!00007ff827e18bcf() 未知 ntdll.dll!00007ff827e415d6() 未知 ntdll.dll!00007ff827e411cd() 未知 kernel32.dll!00007ff825b77fcb() 未知 ucrtbased.dll!00007fffa1441eda() 未知 ucrtbased.dll!00007fffa1441e85() 未知 ucrtbased.dll!00007fffa14421f6() 未知 MediaServer.exe!__scrt_common_main_seh() 行 297 C++ MediaServer.exe!__scrt_common_main() 行 331 C++ MediaServer.exe!mainCRTStartup(void * __formal) 行 17 C++ kernel32.dll!00007ff825b7259d() 未知 ntdll.dll!00007ff827e4af78() 未知

原因分析:

在ZLMediakit的退出流程中,当程序退出的时候,会回收资源,包括EventPoller的回收,目前的EventPoller的析构会向pipe发送信号,然后触发poller线程激活,设置_exit_flag,并且跳出eventloop。如果这里的wirte失败的话(实际测试结果,这里可能出现报错,在windows上,错误号是10093),就可能导致eventloop线程处于阻塞状态,无法退出系统。 引起上述失败的原因就在于在系统退出的析构过程中,socket的调用是不安全的,所以我们在ZLTookKit这里,对eventpoller增加releasePool,方便外部调用者在适当的时候主动释放所有的eventloop,从而避免卡死的问题。

其他

关于底层锁住的原因参考https://github.com/ZLMediaKit/ZLMediaKit/issues/4580中的讨论

jeyawn avatar Dec 05 '25 13:12 jeyawn

CLA assistant check
All committers have signed the CLA.

CLAassistant avatar Dec 05 '25 13:12 CLAassistant

EventPollerPool是TaskExecutorGetterImp的子类,我觉得没必要重复定义releasePool()和releaseAllEventPoller()两个函数,只需要在TaskExecutorGetterImp基类实现一个release()函数就行了。

xia-chu avatar Dec 09 '25 02:12 xia-chu

EventPollerPool是TaskExecutorGetterImp的子类,我觉得没必要重复定义releasePool()和releaseAllEventPoller()两个函数,只需要在TaskExecutorGetterImp基类实现一个release()函数就行了。

嗯,我也在想想,主动释放目前好像还是会发生卡住的问题,只是概率在我这里降低了很多,我再看看

jeyawn avatar Dec 13 '25 06:12 jeyawn