This is an automated email from the ASF dual-hosted git repository.

guangning pushed a commit to branch branch-2.5
in repository https://gitbox.apache.org/repos/asf/pulsar.git

commit 765aa020d14c50ed3f8a096433777570301a0a63
Author: Nick Rivera <[email protected]>
AuthorDate: Thu Feb 13 17:14:39 2020 -0800

    [Issue 4070][pulsar-client-cpp] Fix for possible deadlock when closing 
Pulsar client (#6277)
    
    * Attempt at fixing deadlock during client.close()
    
    * Fixed formatting
    
    * Detach the worker thread in the destructor of ExecutorService if it is 
still unable to be joined
    
    * Possible formatting fixes
---
 pulsar-client-cpp/lib/ExecutorService.cc | 20 ++++++++++++++------
 pulsar-client-cpp/lib/ExecutorService.h  |  2 +-
 2 files changed, 15 insertions(+), 7 deletions(-)

diff --git a/pulsar-client-cpp/lib/ExecutorService.cc 
b/pulsar-client-cpp/lib/ExecutorService.cc
index 75f465d..8de0459 100644
--- a/pulsar-client-cpp/lib/ExecutorService.cc
+++ b/pulsar-client-cpp/lib/ExecutorService.cc
@@ -29,7 +29,14 @@ ExecutorService::ExecutorService()
       work_(new BackgroundWork(*io_service_)),
       worker_(std::bind(&ExecutorService::startWorker, this, io_service_)) {}
 
-ExecutorService::~ExecutorService() { close(); }
+ExecutorService::~ExecutorService() {
+    close();
+    // If the worker_ is still not joinable at this point just detach
+    // the thread so its destructor does not terminate the app
+    if (worker_.joinable()) {
+        worker_.detach();
+    }
+}
 
 void ExecutorService::startWorker(std::shared_ptr<boost::asio::io_service> 
io_service) { io_service_->run(); }
 
@@ -59,11 +66,12 @@ DeadlineTimerPtr ExecutorService::createDeadlineTimer() {
 }
 
 void ExecutorService::close() {
-    // Ensure this service has not already been closed. This is
-    // because worker_.join() is not re-entrant on Windows
-    if (work_) {
-        io_service_->stop();
-        work_.reset();
+    io_service_->stop();
+    work_.reset();
+    // If this thread is attempting to join itself, do not. The destructor's
+    // call to close will handle joining if it does not occur here. This also 
ensures
+    // join is not called twice since it is not re-entrant on windows
+    if (std::this_thread::get_id() != worker_.get_id() && worker_.joinable()) {
         worker_.join();
     }
 }
diff --git a/pulsar-client-cpp/lib/ExecutorService.h 
b/pulsar-client-cpp/lib/ExecutorService.h
index 883d4ce..b673b79 100644
--- a/pulsar-client-cpp/lib/ExecutorService.h
+++ b/pulsar-client-cpp/lib/ExecutorService.h
@@ -70,7 +70,7 @@ class PULSAR_PUBLIC ExecutorService : private 
boost::noncopyable {
      * background invoking async handlers as they are finished and result is 
available from
      * io_service
      */
-    boost::asio::detail::thread worker_;
+    std::thread worker_;
 };
 
 typedef std::shared_ptr<ExecutorService> ExecutorServicePtr;

Reply via email to