Making crossplat::threadpool::shared_instance() safe to use in cpprest DLL #611
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This took me a while to track down. While investigating PR #608, on Windows / VS 2013, I found that many of the test suites would more often than not complete successfully, but then the test_runner exe wouldn't exit. I found this was due to deadlock while the
test_module_loader
was unloading DLLs. The culprit is the destruction of thestatic threadpool_impl
insidecrossplat::threadpool::shared_instance()
. Its destructor must join all the threads in the pool. This is likely to deadlock because inDllMain
atDLL_PROCESS_DETACH
, the loader lock is held, and the thread to be joined therefore cannot signal thread termination byDLL_THREAD_DETACH
. (A quick web search finds many explanations of this, including some good ones on Microsoft's own The Old New Thing.)Why hasn't this been reported before? I assume mostly on Windows, people aren't using e.g.
CPPREST_FORCE_HTTP_LISTENER_ASIO
or if they are, they aren't explicitly unloading the cpprest DLL until process termination.There are two approaches to fixing this:
shared_ptr<threadpool>
, could work.Assuming 2 is preferable, I ultimately discovered that asio already provides the mechanism to solve this exact issue. And it has been present and documented in asio since at least Boost 1.37.0, so although it is in the namespace
boost::asio::detail
I think it can be relied on. I have tried Boost 1.65.1 (current) and Boost 1.54.0 (cpprestsdk's documented minimum version). I have run tests on both Windows and Linux platforms.Implementation notes:
#if defined(CPPREST_PTHREADS)
alternative, butboost::asio::detail::thread
picks Windows threads or POSIX threads (or falls back tostd::thread
) appropriately anyway, so the code is now mostly simpler than it was too.std::vector<boost::asio::detail::thread>
, but for some reason thethread
type isn't movable, hence the use ofstd::unique_ptr
.