Implement join with timeout (and detach).

Under certain situations (notably JNI shutdown), it's possible to get
deadlock when using thread join().  To avoid this, implement a timeout.
Normally we try to simply join the thread, but if it times out, we
detach the thread instead.
This commit is contained in:
Peter Johnson
2015-10-09 23:50:01 -07:00
parent d77b3d788e
commit dd0e3e4abb
8 changed files with 166 additions and 12 deletions

View File

@@ -54,6 +54,11 @@ void DispatcherBase::StartServer(StringRef persist_filename,
if (m_active) return;
m_active = true;
}
{
std::lock_guard<std::mutex> lock(m_shutdown_mutex);
m_dispatch_shutdown = false;
m_clientserver_shutdown = false;
}
m_server = true;
m_persist_filename = persist_filename;
m_server_acceptor = std::move(acceptor);
@@ -87,6 +92,11 @@ void DispatcherBase::StartClient(
if (m_active) return;
m_active = true;
}
{
std::lock_guard<std::mutex> lock(m_shutdown_mutex);
m_dispatch_shutdown = false;
m_clientserver_shutdown = false;
}
m_server = false;
using namespace std::placeholders;
@@ -110,9 +120,27 @@ void DispatcherBase::Stop() {
// wake up server thread by shutting down the socket
if (m_server_acceptor) m_server_acceptor->shutdown();
// join threads
if (m_dispatch_thread.joinable()) m_dispatch_thread.join();
if (m_clientserver_thread.joinable()) m_clientserver_thread.join();
// join threads, with timeout
if (m_dispatch_thread.joinable()) {
std::unique_lock<std::mutex> lock(m_shutdown_mutex);
auto timeout_time =
std::chrono::steady_clock::now() + std::chrono::seconds(1);
if (m_dispatch_shutdown_cv.wait_until(lock, timeout_time,
[&] { return m_dispatch_shutdown; }))
m_dispatch_thread.join();
else
m_dispatch_thread.detach(); // timed out, detach it
}
if (m_clientserver_thread.joinable()) {
std::unique_lock<std::mutex> lock(m_shutdown_mutex);
auto timeout_time =
std::chrono::steady_clock::now() + std::chrono::seconds(1);
if (m_clientserver_shutdown_cv.wait_until(
lock, timeout_time, [&] { return m_clientserver_shutdown; }))
m_clientserver_thread.join();
else
m_clientserver_thread.detach(); // timed out, detach it
}
std::vector<std::shared_ptr<NetworkConnection>> conns;
{
@@ -229,6 +257,13 @@ void DispatcherBase::DispatchThreadMain() {
}
}
}
// use condition variable to signal thread shutdown
{
std::lock_guard<std::mutex> lock(m_shutdown_mutex);
m_dispatch_shutdown = true;
m_dispatch_shutdown_cv.notify_one();
}
}
void DispatcherBase::QueueOutgoing(std::shared_ptr<Message> msg,
@@ -248,7 +283,7 @@ void DispatcherBase::QueueOutgoing(std::shared_ptr<Message> msg,
void DispatcherBase::ServerThreadMain() {
if (m_server_acceptor->start() != 0) {
m_active = false;
return;
goto done;
}
while (m_active) {
auto stream = m_server_acceptor->accept();
@@ -274,6 +309,14 @@ void DispatcherBase::ServerThreadMain() {
conn->Start();
}
}
done:
// use condition variable to signal thread shutdown
{
std::lock_guard<std::mutex> lock(m_shutdown_mutex);
m_clientserver_shutdown = true;
m_clientserver_shutdown_cv.notify_one();
}
}
void DispatcherBase::ClientThreadMain(
@@ -306,6 +349,13 @@ void DispatcherBase::ClientThreadMain(
m_do_reconnect = false;
m_reconnect_cv.wait(lock, [&] { return !m_active || m_do_reconnect; });
}
// use condition variable to signal thread shutdown
{
std::lock_guard<std::mutex> lock(m_shutdown_mutex);
m_clientserver_shutdown = true;
m_clientserver_shutdown_cv.notify_one();
}
}
bool DispatcherBase::ClientHandshake(