Files
libreoffice/include/comphelper/threadpool.hxx
Michael Stahl bdaa13a877 comphelper:: fix MSVC hang in ThreadPool::shutdown(), try #2
This takes a different approach than commit
9899ffd244.

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.meeks@collabora.com>
Tested-by: Jenkins <ci@libreoffice.org>
2017-03-21 16:15:36 +00:00

104 lines
3.1 KiB
C++

/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*
* This file is part of the LibreOffice project.
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#ifndef INCLUDED_COMPHELPER_THREADPOOL_HXX
#define INCLUDED_COMPHELPER_THREADPOOL_HXX
#include <sal/config.h>
#include <rtl/ref.hxx>
#include <comphelper/comphelperdllapi.h>
#include <mutex>
#include <thread>
#include <condition_variable>
#include <vector>
#include <memory>
namespace comphelper
{
class ThreadTaskTag;
class ThreadPool;
class COMPHELPER_DLLPUBLIC ThreadTask
{
friend class ThreadPool;
std::shared_ptr<ThreadTaskTag> mpTag;
/// execute and delete this task
void execAndDelete();
protected:
/// override to get your task performed by the pool
virtual void doWork() = 0;
/// once pushed ThreadTasks are destroyed by the pool
virtual ~ThreadTask() {}
public:
ThreadTask(const std::shared_ptr<ThreadTaskTag>& pTag);
};
/// A very basic thread-safe thread pool implementation
class COMPHELPER_DLLPUBLIC ThreadPool final
{
public:
/// returns a pointer to a shared pool with optimal thread
/// count for the CPU
static ThreadPool& getSharedOptimalPool();
static std::shared_ptr<ThreadTaskTag> createThreadTaskTag();
static bool isTaskTagDone(const std::shared_ptr<ThreadTaskTag>&);
/// returns a configurable max-concurrency
/// limit to avoid spawning an unnecessarily
/// large number of threads on high-core boxes.
/// MAX_CONCURRENCY env. var. controls the cap.
static sal_Int32 getPreferredConcurrency();
ThreadPool( sal_Int32 nWorkers );
~ThreadPool();
/// push a new task onto the work queue
void pushTask( ThreadTask *pTask /* takes ownership */ );
/// wait until all queued tasks associated with the tag are completed
void waitUntilDone(const std::shared_ptr<ThreadTaskTag>&);
/// return the number of live worker threads
sal_Int32 getWorkerCount() const { return mnWorkers; }
/// wait until all work is completed, then join all threads
void shutdown();
private:
ThreadPool(const ThreadPool&) = delete;
ThreadPool& operator=(const ThreadPool&) = delete;
class ThreadWorker;
friend class ThreadWorker;
/** Pop a work task
@param bWait - if set wait until task present or termination
@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;
};
} // namespace comphelper
#endif // INCLUDED_COMPHELPER_THREADPOOL_HXX
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */