Skip to content

Making crossplat::threadpool::shared_instance() safe to use in cpprest DLL #611

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Release/include/pplx/threadpool.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ using java_local_ref = std::unique_ptr<typename std::remove_pointer<T>::type, ja
class threadpool
{
public:
static threadpool& shared_instance();
_ASYNCRTIMP static threadpool& shared_instance();
_ASYNCRTIMP static std::unique_ptr<threadpool> __cdecl construct(size_t num_threads);

virtual ~threadpool() = default;
Expand Down
65 changes: 34 additions & 31 deletions Release/src/pplx/threadpool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,7 @@
#if !defined(CPPREST_EXCLUDE_WEBSOCKETS) || !defined(_WIN32)
#include "pplx/threadpool.h"

#if !defined(_WIN32)
#define CPPREST_PTHREADS
#endif

#if defined(CPPREST_PTHREADS)
#include <pthread.h>
#else
#include <thread>
#endif

#include <boost/asio/detail/thread.hpp>
#include <vector>

#if defined(__ANDROID__)
Expand All @@ -44,27 +35,14 @@ struct threadpool_impl final : crossplat::threadpool
m_service.stop();
for (auto iter = m_threads.begin(); iter != m_threads.end(); ++iter)
{
#if defined(CPPREST_PTHREADS)
pthread_t t = *iter;
void* res;
pthread_join(t, &res);
#else
iter->join();
#endif
(*iter)->join();
}
}

private:
void add_thread()
{
#ifdef CPPREST_PTHREADS
pthread_t t;
auto result = pthread_create(&t, nullptr, &thread_start, this);
if (result == 0)
m_threads.push_back(t);
#else
m_threads.push_back(std::thread(&thread_start, this));
#endif
m_threads.push_back(std::unique_ptr<boost::asio::detail::thread>(new boost::asio::detail::thread([&]{ thread_start(this); })));
}

#if defined(__ANDROID__)
Expand All @@ -89,11 +67,7 @@ struct threadpool_impl final : crossplat::threadpool
return arg;
}

#if defined(CPPREST_PTHREADS)
std::vector<pthread_t> m_threads;
#else
std::vector<std::thread> m_threads;
#endif
std::vector<std::unique_ptr<boost::asio::detail::thread>> m_threads;
boost::asio::io_service::work m_work;
};
}
Expand Down Expand Up @@ -133,6 +107,35 @@ threadpool& threadpool::shared_instance()
return s_shared;
}

#elif defined(_WIN32)

// if linked into a DLL, the threadpool shared instance will be destroyed at DLL_PROCESS_DETACH,
// at which stage joining threads causes deadlock, hence this dance
threadpool& threadpool::shared_instance()
{
static bool terminate_threads = false;
static struct restore_terminate_threads
{
~restore_terminate_threads()
{
boost::asio::detail::thread::set_terminate_threads(terminate_threads);
}
} destroyed_after;

static threadpool_impl s_shared(40);

static struct enforce_terminate_threads
{
~enforce_terminate_threads()
{
terminate_threads = boost::asio::detail::thread::terminate_threads();
boost::asio::detail::thread::set_terminate_threads(true);
}
} destroyed_before;

return s_shared;
}

#else

// initialize the static shared threadpool
Expand All @@ -156,4 +159,4 @@ std::unique_ptr<crossplat::threadpool> crossplat::threadpool::construct(size_t n
{
return std::unique_ptr<crossplat::threadpool>(new threadpool_impl(num_threads));
}
#endif
#endif