Skip to content

Commit

Permalink
Refactoring: replace DotRunnerQueue and DotWorkerThread by ThreadPool
Browse files Browse the repository at this point in the history
  • Loading branch information
doxygen committed May 21, 2023
1 parent 12d0aed commit bcc35bd
Show file tree
Hide file tree
Showing 7 changed files with 16 additions and 159 deletions.
60 changes: 13 additions & 47 deletions src/dot.cpp
Expand Up @@ -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<size_t>(Config_getInt(DOT_NUM_THREADS)))
{
m_queue = new DotRunnerQueue;
int i;
int dotNumThreads = Config_getInt(DOT_NUM_THREADS);
if (dotNumThreads!=1)
{
for (i=0;i<dotNumThreads;i++)
{
DotWorkerThreadPtr thread(new DotWorkerThread(m_queue));
thread->start();
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)
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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)
{
Expand All @@ -196,36 +176,22 @@ bool DotManager::run() const
}
else // use multiple threads to run instances of dot in parallel
{
std::vector< std::future<void> > 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;i<m_workers.size();i++)
{
m_queue->enqueue(0); // add terminator for each worker
}
// wait for the workers to finish
for (i=0;i<m_workers.size();i++)
{
m_workers.at(i)->wait();
}
}
if (setPath)
{
Expand Down
9 changes: 3 additions & 6 deletions src/dot.h
Expand Up @@ -18,6 +18,7 @@

#include <map>

#include "threadpool.h"
#include "qcstring.h"
#include "dotgraph.h" // only for GraphOutputFormat
#include "dotfilepatcher.h"
Expand All @@ -28,26 +29,22 @@ class DotRunner;
class DotRunnerQueue;
class TextStream;

using DotWorkerThreadPtr = std::unique_ptr< DotWorkerThread, NonTerminatingDeleter<DotWorkerThread > >;

/** 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();
virtual ~DotManager();

std::map<std::string, std::unique_ptr<DotRunner> > m_runners;
std::map<std::string, DotFilePatcher> m_filePatchers;
DotRunnerQueue *m_queue;
std::vector< DotWorkerThreadPtr > m_workers;
ThreadPool m_workers;
};

void writeDotGraphFromFile(const QCString &inFile,const QCString &outDir,
Expand Down
56 changes: 0 additions & 56 deletions src/dotrunner.cpp
Expand Up @@ -362,59 +362,3 @@ bool DotRunner::run()
}


//--------------------------------------------------------------------

void DotRunnerQueue::enqueue(DotRunner *runner)
{
std::lock_guard<std::mutex> locker(m_mutex);
m_queue.push(runner);
m_bufferNotEmpty.notify_all();
}

DotRunner *DotRunnerQueue::dequeue()
{
std::unique_lock<std::mutex> 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<std::mutex> 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<std::thread>(&DotWorkerThread::run, this);
}
29 changes: 0 additions & 29 deletions src/dotrunner.h
Expand Up @@ -68,33 +68,4 @@ class DotRunner
std::vector<DotJob> 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<DotRunner *> 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<std::thread> m_thread;
DotRunnerQueue *m_queue;
};

#endif
11 changes: 0 additions & 11 deletions src/doxygen.h
Expand Up @@ -136,17 +136,6 @@ class Doxygen
static std::mutex addExampleMutex;
};

/** Deleter that only deletes an object if doxygen is not already terminating */
template<class T>
struct NonTerminatingDeleter
{
void operator()(T *obj)
{
if (!Doxygen::terminating) delete obj;
}
};


void initDoxygen();
void readConfiguration(int argc, char **argv);
void checkConfiguration();
Expand Down
9 changes: 0 additions & 9 deletions src/portable.cpp
Expand Up @@ -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();
Expand Down
1 change: 0 additions & 1 deletion src/portable.h
Expand Up @@ -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();
Expand Down

0 comments on commit bcc35bd

Please sign in to comment.