From bcc35bd61c32b45a07a73cce77eef90a77618e51 Mon Sep 17 00:00:00 2001 From: Dimitri van Heesch Date: Sun, 21 May 2023 15:02:22 +0200 Subject: [PATCH] Refactoring: replace DotRunnerQueue and DotWorkerThread by ThreadPool --- src/dot.cpp | 60 ++++++++++------------------------------------- src/dot.h | 9 +++---- src/dotrunner.cpp | 56 ------------------------------------------- src/dotrunner.h | 29 ----------------------- src/doxygen.h | 11 --------- src/portable.cpp | 9 ------- src/portable.h | 1 - 7 files changed, 16 insertions(+), 159 deletions(-) diff --git a/src/dot.cpp b/src/dot.cpp index 956eac199cb..11ac2a4544f 100644 --- a/src/dot.cpp +++ b/src/dot.cpp @@ -81,32 +81,12 @@ DotManager *DotManager::instance() return &theInstance; } -DotManager::DotManager() : m_runners(), m_filePatchers() +DotManager::DotManager() : m_runners(), m_filePatchers(), m_workers(static_cast(Config_getInt(DOT_NUM_THREADS))) { - m_queue = new DotRunnerQueue; - int i; - int dotNumThreads = Config_getInt(DOT_NUM_THREADS); - if (dotNumThreads!=1) - { - for (i=0;istart(); - if (thread->isRunning()) - { - m_workers.push_back(std::move(thread)); - } - else // no more threads available! - { - } - } - ASSERT(m_workers.size()>0); - } } DotManager::~DotManager() { - if (!Doxygen::terminating) delete m_queue; } DotRunner* DotManager::createRunner(const QCString &absDotName, const QCString& md5Hash) @@ -145,19 +125,19 @@ DotFilePatcher *DotManager::createFilePatcher(const QCString &fileName) return &(rv.first->second); } -bool DotManager::run() const +bool DotManager::run() { size_t numDotRuns = m_runners.size(); size_t numFilePatchers = m_filePatchers.size(); if (numDotRuns+numFilePatchers>1) { - if (m_workers.size()==0) + if (Config_getInt(DOT_NUM_THREADS)<=1) { msg("Generating dot graphs in single threaded mode...\n"); } else { - msg("Generating dot graphs using %zu parallel threads...\n",std::min(numDotRuns+numFilePatchers,m_workers.size())); + msg("Generating dot graphs using %d parallel threads...\n",Config_getInt(DOT_NUM_THREADS)); } } size_t i=1; @@ -185,7 +165,7 @@ bool DotManager::run() const } // fill work queue with dot operations size_t prev=1; - if (m_workers.size()==0) // no threads to work with + if (Config_getInt(DOT_NUM_THREADS)<=1) // no threads to work with { for (auto & dr : m_runners) { @@ -196,36 +176,22 @@ bool DotManager::run() const } else // use multiple threads to run instances of dot in parallel { + std::vector< std::future > results; for (auto & dr: m_runners) { - m_queue->enqueue(dr.second.get()); - } - // wait for the queue to become empty - while ((i=m_queue->size())>0) - { - i = numDotRuns - i; - while (i>=prev) + DotRunner *runner = dr.second.get(); + auto process = [runner]() { - msg("Running dot for graph %zu/%zu\n",prev,numDotRuns); - prev++; - } - Portable::sleep(100); + runner->run(); + }; + results.emplace_back(m_workers.queue(process)); } - while (numDotRuns>=prev) + for (auto &f : results) { + f.get(); msg("Running dot for graph %zu/%zu\n",prev,numDotRuns); prev++; } - // signal the workers we are done - for (i=0;ienqueue(0); // add terminator for each worker - } - // wait for the workers to finish - for (i=0;iwait(); - } } if (setPath) { diff --git a/src/dot.h b/src/dot.h index 87f1d39bb00..a22dab78749 100644 --- a/src/dot.h +++ b/src/dot.h @@ -18,6 +18,7 @@ #include +#include "threadpool.h" #include "qcstring.h" #include "dotgraph.h" // only for GraphOutputFormat #include "dotfilepatcher.h" @@ -28,17 +29,14 @@ class DotRunner; class DotRunnerQueue; class TextStream; -using DotWorkerThreadPtr = std::unique_ptr< DotWorkerThread, NonTerminatingDeleter >; - /** Singleton that manages parallel dot invocations and patching files for embedding image maps */ class DotManager { public: static DotManager *instance(); - //static void deleteInstance(); DotRunner* createRunner(const QCString& absDotName, const QCString& md5Hash); DotFilePatcher *createFilePatcher(const QCString &fileName); - bool run() const; + bool run(); private: DotManager(); @@ -46,8 +44,7 @@ class DotManager std::map > m_runners; std::map m_filePatchers; - DotRunnerQueue *m_queue; - std::vector< DotWorkerThreadPtr > m_workers; + ThreadPool m_workers; }; void writeDotGraphFromFile(const QCString &inFile,const QCString &outDir, diff --git a/src/dotrunner.cpp b/src/dotrunner.cpp index f54618e21bb..807243df9d1 100644 --- a/src/dotrunner.cpp +++ b/src/dotrunner.cpp @@ -362,59 +362,3 @@ bool DotRunner::run() } -//-------------------------------------------------------------------- - -void DotRunnerQueue::enqueue(DotRunner *runner) -{ - std::lock_guard locker(m_mutex); - m_queue.push(runner); - m_bufferNotEmpty.notify_all(); -} - -DotRunner *DotRunnerQueue::dequeue() -{ - std::unique_lock locker(m_mutex); - - // wait until something is added to the queue - m_bufferNotEmpty.wait(locker, [this]() { return !m_queue.empty(); }); - - DotRunner *result = m_queue.front(); - m_queue.pop(); - return result; -} - -size_t DotRunnerQueue::size() const -{ - std::lock_guard locker(m_mutex); - return m_queue.size(); -} - -//-------------------------------------------------------------------- - -DotWorkerThread::DotWorkerThread(DotRunnerQueue *queue) - : m_queue(queue) -{ -} - -DotWorkerThread::~DotWorkerThread() -{ - if (isRunning()) - { - wait(); - } -} - -void DotWorkerThread::run() -{ - DotRunner *runner; - while ((runner=m_queue->dequeue())) - { - runner->run(); - } -} - -void DotWorkerThread::start() -{ - assert(!m_thread); - m_thread = std::make_unique(&DotWorkerThread::run, this); -} diff --git a/src/dotrunner.h b/src/dotrunner.h index 035b34d0b68..054dcf4ab0f 100644 --- a/src/dotrunner.h +++ b/src/dotrunner.h @@ -68,33 +68,4 @@ class DotRunner std::vector m_jobs; }; -/** Queue of dot jobs to run. */ -// all methods are thread save -class DotRunnerQueue -{ - public: - void enqueue(DotRunner *runner); - DotRunner *dequeue(); - size_t size() const; - private: - std::condition_variable m_bufferNotEmpty; - std::queue m_queue; - mutable std::mutex m_mutex; -}; - -/** Worker thread to execute a dot run */ -class DotWorkerThread -{ - public: - DotWorkerThread(DotRunnerQueue *queue); - ~DotWorkerThread(); - void run(); - void start(); - bool isRunning() const { return m_thread && m_thread->joinable(); } - void wait() { m_thread->join(); } - private: - std::unique_ptr m_thread; - DotRunnerQueue *m_queue; -}; - #endif diff --git a/src/doxygen.h b/src/doxygen.h index 2b46bb5ed49..c5003e01194 100644 --- a/src/doxygen.h +++ b/src/doxygen.h @@ -136,17 +136,6 @@ class Doxygen static std::mutex addExampleMutex; }; -/** Deleter that only deletes an object if doxygen is not already terminating */ -template -struct NonTerminatingDeleter -{ - void operator()(T *obj) - { - if (!Doxygen::terminating) delete obj; - } -}; - - void initDoxygen(); void readConfiguration(int argc, char **argv); void checkConfiguration(); diff --git a/src/portable.cpp b/src/portable.cpp index ac13afa4ea0..8accdc9468f 100644 --- a/src/portable.cpp +++ b/src/portable.cpp @@ -502,15 +502,6 @@ int Portable::pclose(FILE *stream) #endif } -void Portable::sleep(int ms) -{ -#if defined(_WIN32) && !defined(__CYGWIN__) - Sleep(ms); -#else - usleep(1000*ms); -#endif -} - bool Portable::isAbsolutePath(const QCString &fileName) { const char *fn = fileName.data(); diff --git a/src/portable.h b/src/portable.h index 3aa72767df6..8d2674a682d 100644 --- a/src/portable.h +++ b/src/portable.h @@ -33,7 +33,6 @@ namespace Portable FILE * popen(const QCString &name,const QCString &type); int pclose(FILE *stream); double getSysElapsedTime(); - void sleep(int ms); bool isAbsolutePath(const QCString &fileName); void correct_path(); void setShortDir();