vsg-dev / vsgExamples

Example programs that test and illustrate how to use the VSG and optional add-on libraries
MIT License
148 stars 67 forks source link

Examples abort on shutdown when run in Debug #315

Closed lufriem closed 3 months ago

lufriem commented 3 months ago

Running various of the example applications (vsgCamera, vsgInput, ..) in the Debug configuration, I noticed that they all seem to call abort() on shutdown (if I quit them by closing their window or by pressing ESC). On the command line I get the message

D:\a_work\1\s\src\vctools\crt\github\stl\src\mutex.cpp(49): mutex destroyed while busy

I'm running the Debug configuration, built from the tip of the current 'master' branches, Windows 10 Visual Studio 2022 (17.9.7). Release seem to work/shut down fine

The call stack is super deep, sorry

ucrtbased.dll!issue_debug_notification(const wchar_t const message) Line 28 C++ ucrtbased.dll!__acrt_report_runtime_error(const wchar_t message) Line 154 C++ ucrtbased.dll!abort() Line 61 C++ msvcp140d.dll!_Thrd_abort(const char msg) Line 22 C++ msvcp140d.dll!_Mtx_destroy_in_situ(_Mtx_internal_imp_t mtx) Line 51 C++ vsginput.exe!std::_Mutex_base::~_Mutex_base() Line 50 C++ vsginput.exe!std::mutex::~mutex() C++ vsginput.exe!vsg::DescriptorPool::~DescriptorPool() Line 58 C++ [External Code] vsginput.exe!vsg::Object::_attemptDelete() Line 95 C++ vsginput.exe!vsg::Object::unref() Line 117 C++ vsginput.exe!vsg::ref_ptr::operator=(vsg::DescriptorPool ptr) Line 91 C++ vsginput.exe!vsg::DescriptorPool::freeDescriptorSet(vsg::ref_ptr dsi) Line 124 C++ vsginput.exe!vsg::DescriptorSet::Implementation::recycle(vsg::ref_ptr & dsi) Line 160 C++ vsginput.exe!vsg::DescriptorSet::release() Line 90 C++ vsginput.exe!vsg::DescriptorSet::~DescriptorSet() Line 42 C++ [External Code] vsginput.exe!vsg::Object::_attemptDelete() Line 95 C++ vsginput.exe!vsg::Object::unref() Line 117 C++ vsginput.exe!vsg::ref_ptr::~ref_ptr() Line 70 C++ vsginput.exe!vsg::BindDescriptorSet::~BindDescriptorSet() Line 154 C++ [External Code] vsginput.exe!vsg::Object::_attemptDelete() Line 95 C++ vsginput.exe!vsg::Object::unref() Line 117 C++ vsginput.exe!vsg::ref_ptr::~ref_ptr() Line 70 C++ [External Code] vsginput.exe!vsg::SharedObjects::~SharedObjects() Line 15 C++ [External Code] vsginput.exe!vsg::Object::_attemptDelete() Line 95 C++ vsginput.exe!vsg::Object::unref() Line 117 C++ vsginput.exe!vsg::ref_ptr::~ref_ptr() Line 70 C++ [External Code] vsginput.exe!vsg::Object::_attemptDelete() Line 95 C++ vsginput.exe!vsg::Object::unref() Line 117 C++ vsginput.exe!vsg::ref_ptr::~ref_ptr() Line 70 C++ [External Code] vsginput.exe!vsg::Object::_attemptDelete() Line 95 C++ vsginput.exe!vsg::Object::unref() Line 117 C++ vsginput.exe!vsg::ref_ptr::~ref_ptr() Line 70 C++ [External Code] vsginput.exe!vsg::Group::~Group() Line 34 C++ [External Code] vsginput.exe!vsg::Object::_attemptDelete() Line 95 C++ vsginput.exe!vsg::Object::unref() Line 117 C++ vsginput.exe!vsg::ref_ptr::~ref_ptr() Line 70 C++ vsginput.exe!main(int argc, char * argv) Line 393 C++

I hope it's just me maybe building vsg incorrectly or something..

lufriem commented 3 months ago

Soo I think

void DescriptorPool::freeDescriptorSet(ref_ptr<DescriptorSet::Implementation> dsi)

is to blame.. what I think happens is

robertosfield commented 3 months ago

I have moved the scoped_lock section into a local scope to ensure the mutex is released before there is a chance of the DescriptroPool being unreferenced:

https://github.com/vsg-dev/VulkanSceneGraph/commit/0746b3c7e7abee7fba730b8e6bc5099a226082de

Could you try this out?

lufriem commented 3 months ago

Yes Debug configuration runs fine with that change :)

I thought about proposing such a change but will this not lead to a possible race condition between the mutex being released and the descriptor pool being destroyed? I guess not because ref_ptr is itself thread-safe? And the mutex is there to protect the DescriptorPool members, not DescriptorSet::Implementation's..

robertosfield commented 3 months ago

Thanks for testing. The Object::_referenceCount is an atomic so is ref_ptr<> calls to ref() and unref() are thread safe.