comphelper/source/misc/threadpool.cxx |   39 +++++++++++++++++++++++++---------
 include/comphelper/threadpool.hxx     |    4 ++-
 2 files changed, 32 insertions(+), 11 deletions(-)

New commits:
commit bdaa13a87744e424d3c210fc7f3f9e4f199d8279
Author: Michael Stahl <mst...@redhat.com>
Date:   Tue Mar 21 15:18:01 2017 +0100

    comphelper:: fix MSVC hang in ThreadPool::shutdown(), try #2
    
    This takes a different approach than commit
    9899ffd244dd367ba69dffe1f21f4f0222064a46.
    
    Change the ThreadPool to automatically shutdown and join all threads
    whenever waitUntilDone() is called.  Then start the threads again
    in pushTask().
    
    Because the ThreadPool is meant to be used synchronously with
    waitUntilDone() called after adding all required tasks, this should
    obviate the need to call shutdown() before process exit, as
    there won't be any threads running at that point.
    
    Change-Id: I2b8e639004a94cf05ccb4522aa1f0d3dac88a936
    Reviewed-on: https://gerrit.libreoffice.org/35510
    Reviewed-by: Michael Meeks <michael.me...@collabora.com>
    Tested-by: Jenkins <c...@libreoffice.org>

diff --git a/comphelper/source/misc/threadpool.cxx 
b/comphelper/source/misc/threadpool.cxx
index 712009d8a2b4..3aaf344c3ba8 100644
--- a/comphelper/source/misc/threadpool.cxx
+++ b/comphelper/source/misc/threadpool.cxx
@@ -75,21 +75,20 @@ public:
     }
 };
 
-ThreadPool::ThreadPool( sal_Int32 nWorkers ) :
-    mbTerminate( false )
+ThreadPool::ThreadPool(sal_Int32 nWorkers)
+    : mbTerminate(true)
+    , mnWorkers(nWorkers)
 {
-    std::unique_lock< std::mutex > aGuard( maMutex );
-
-    for( sal_Int32 i = 0; i < nWorkers; i++ )
-        maWorkers.push_back( new ThreadWorker( this ) );
-
-    for(rtl::Reference<ThreadWorker> & rpWorker : maWorkers)
-        rpWorker->launch();
 }
 
 ThreadPool::~ThreadPool()
 {
-    shutdown();
+    // note: calling shutdown from global variable dtor blocks forever on Win7
+    // note2: there isn't enough MSVCRT left on exit to call assert() properly
+    // so these asserts just print something to stderr but exit status is
+    // still 0, but hopefully they will be more helpful on non-WNT platforms
+    assert(mbTerminate);
+    assert(maTasks.empty());
 }
 
 struct ThreadPoolStatic : public rtl::StaticWithInit< std::shared_ptr< 
ThreadPool >,
@@ -136,7 +135,11 @@ void ThreadPool::shutdown()
         return;
 
     std::unique_lock< std::mutex > aGuard( maMutex );
+    shutdownLocked(aGuard);
+}
 
+void ThreadPool::shutdownLocked(std::unique_lock<std::mutex>& aGuard)
+{
     if( maWorkers.empty() )
     { // no threads at all -> execute the work in-line
         ThreadTask *pTask;
@@ -173,6 +176,14 @@ void ThreadPool::pushTask( ThreadTask *pTask )
 {
     std::unique_lock< std::mutex > aGuard( maMutex );
 
+    mbTerminate = false;
+
+    if (maWorkers.size() < mnWorkers && maWorkers.size() <= maTasks.size())
+    {
+        maWorkers.push_back( new ThreadWorker( this ) );
+        maWorkers.back()->launch();
+    }
+
     pTask->mpTag->onTaskPushed();
     maTasks.insert( maTasks.begin(), pTask );
 
@@ -217,6 +228,14 @@ void ThreadPool::waitUntilDone(const 
std::shared_ptr<ThreadTaskTag>& rTag)
     }
 
     rTag->waitUntilDone();
+
+    {
+        std::unique_lock< std::mutex > aGuard( maMutex );
+        if (maTasks.empty()) // check if there are still tasks from another tag
+        {
+            shutdownLocked(aGuard);
+        }
+    }
 }
 
 std::shared_ptr<ThreadTaskTag> ThreadPool::createThreadTaskTag()
diff --git a/include/comphelper/threadpool.hxx 
b/include/comphelper/threadpool.hxx
index 32fcb64198d7..66ade62f3f8f 100644
--- a/include/comphelper/threadpool.hxx
+++ b/include/comphelper/threadpool.hxx
@@ -68,7 +68,7 @@ public:
     void        waitUntilDone(const std::shared_ptr<ThreadTaskTag>&);
 
     /// return the number of live worker threads
-    sal_Int32   getWorkerCount() const { return maWorkers.size(); }
+    sal_Int32   getWorkerCount() const { return mnWorkers; }
 
     /// wait until all work is completed, then join all threads
     void        shutdown();
@@ -85,11 +85,13 @@ private:
         @return a new task to perform, or NULL if list empty or terminated
     */
     ThreadTask *popWorkLocked( std::unique_lock< std::mutex > & rGuard, bool 
bWait );
+    void shutdownLocked(std::unique_lock<std::mutex>&);
 
     /// signalled when all in-progress tasks are complete
     std::mutex              maMutex;
     std::condition_variable maTasksChanged;
     bool                    mbTerminate;
+    std::size_t             mnWorkers;
     std::vector< ThreadTask * >   maTasks;
     std::vector< rtl::Reference< ThreadWorker > > maWorkers;
 };
_______________________________________________
Libreoffice-commits mailing list
libreoffice-comm...@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/libreoffice-commits

Reply via email to