Just tested switching only std::atomic to boost::atomic and it gets the original crash. Then went and only changed std::thread to boost::thread, leaving std::atomic, and the crash is fixed again. So it is definitely the std::thread objects. Still, with my fix, the log is still noting "2 output(s) were remaining" and 2 extra memory leaks as with the original code, so it would seem like using boost::thread is just 'covering up' or something. So now I am leaving std::atomic but changing std::thread to boost::thread everywhere it appears. Just to confirm in case you want to test for yourself, the only other code change is altering #include <thread> to #include <boost/thread.hpp>. Then it's as simple as adding the boost root dir to "Additional Include Libraries" and stage\lib in the boost root dir to "Additional Library Directories. Boost was built using the included bootstrap batch file as per the documentation.
Funny enough, that changed you proposed was the first thing I tried before changing to boost, and it gives a different, worse crash. It's different because the crash notification appears to be from OBS Studio itself and not the bog standard Windows crash message box. And worse because even though the Window closes, the OBS Studio process keeps running in the background until ended through Task Manager.
I must apologize now because I am fairly new to Windows API, C++, and coding in general, so I really don't know much and may be wrong about any number of things. But as you probably know, boost is basically intended to bring older C++ standards up to date, or at least more up to date, with C++11 and future standards.
So in theory boost::thread and std::thread would be the same, but I know many of the boost libraries and in particular boost::thread have some minor differences with the std libraries. I don't know what they are in particular, but my guess would be that, as coded and with my modifications, they are both either leaving open thread handles on module unload or the reference count is getting messed up when the code is exited with the threads left in a joinable state. Hence why OBS Studio log reports "2 output(s) were remaining" and 2 extra memory leaks either way. So either boost::thread must have some way of detecting the potentially fatal error and has some workaround to avoid it, or std::thread is purposefully causing a crash when it detects the memory leaks as some kind of ham-handed debugging. Hope this helps somehow