2018-11-17 21:07:04 +00:00
|
|
|
#ifndef LLARP_THREAD_POOL_HPP
|
|
|
|
#define LLARP_THREAD_POOL_HPP
|
|
|
|
|
2019-01-10 19:41:51 +00:00
|
|
|
#include <util/queue.hpp>
|
|
|
|
#include <util/threading.hpp>
|
2018-11-17 21:07:04 +00:00
|
|
|
|
2019-03-03 20:51:47 +00:00
|
|
|
#include <atomic>
|
2018-11-17 21:07:04 +00:00
|
|
|
#include <functional>
|
|
|
|
#include <thread>
|
|
|
|
#include <vector>
|
|
|
|
|
|
|
|
namespace llarp
|
|
|
|
{
|
|
|
|
namespace thread
|
|
|
|
{
|
|
|
|
class ThreadPool
|
|
|
|
{
|
|
|
|
// Provide an efficient fixed size threadpool. The following attributes
|
|
|
|
// of the threadpool are fixed at construction time:
|
|
|
|
// - the max number of pending jobs
|
|
|
|
// - the number of threads
|
|
|
|
public:
|
|
|
|
using Job = std::function< void() >;
|
|
|
|
using JobQueue = Queue< Job >;
|
|
|
|
|
|
|
|
enum class Status
|
|
|
|
{
|
|
|
|
Stop,
|
|
|
|
Run,
|
|
|
|
Suspend,
|
|
|
|
Drain
|
|
|
|
};
|
|
|
|
|
|
|
|
private:
|
|
|
|
JobQueue m_queue; // The job queue
|
|
|
|
util::Semaphore m_semaphore; // The semaphore for the queue.
|
|
|
|
|
|
|
|
std::atomic_size_t m_idleThreads; // Number of idle threads
|
|
|
|
|
2019-03-03 20:51:47 +00:00
|
|
|
util::Mutex m_mutex;
|
2018-11-17 21:07:04 +00:00
|
|
|
|
|
|
|
std::atomic< Status > m_status;
|
|
|
|
|
2019-03-03 20:51:47 +00:00
|
|
|
size_t m_gateCount GUARDED_BY(m_gateMutex);
|
|
|
|
size_t m_numThreadsReady
|
|
|
|
GUARDED_BY(m_gateMutex); // Threads ready to go through the gate.
|
2018-11-17 21:07:04 +00:00
|
|
|
|
2019-03-03 20:51:47 +00:00
|
|
|
util::Mutex m_gateMutex;
|
2018-11-17 21:07:04 +00:00
|
|
|
|
|
|
|
std::vector< std::thread > m_threads;
|
|
|
|
size_t m_createdThreads;
|
|
|
|
|
|
|
|
void
|
|
|
|
join();
|
|
|
|
|
|
|
|
void
|
|
|
|
runJobs();
|
|
|
|
|
|
|
|
void
|
|
|
|
drainQueue();
|
|
|
|
|
|
|
|
void
|
|
|
|
waitThreads();
|
|
|
|
|
|
|
|
void
|
|
|
|
releaseThreads();
|
|
|
|
|
|
|
|
void
|
|
|
|
interrupt();
|
|
|
|
|
|
|
|
void
|
|
|
|
worker();
|
|
|
|
|
|
|
|
bool
|
|
|
|
spawn();
|
|
|
|
|
2019-03-03 20:51:47 +00:00
|
|
|
bool
|
|
|
|
allThreadsReady() const SHARED_LOCKS_REQUIRED(m_gateMutex)
|
|
|
|
{
|
|
|
|
return m_numThreadsReady == m_threads.size();
|
|
|
|
}
|
|
|
|
|
2018-11-17 21:07:04 +00:00
|
|
|
public:
|
|
|
|
ThreadPool(size_t numThreads, size_t maxJobs);
|
|
|
|
|
|
|
|
~ThreadPool();
|
|
|
|
|
|
|
|
// Disable the threadpool. Calls to `addJob` and `tryAddJob` will fail.
|
|
|
|
// Jobs currently in the pool will not be affected.
|
|
|
|
void
|
|
|
|
disable();
|
|
|
|
|
|
|
|
void
|
|
|
|
enable();
|
|
|
|
|
|
|
|
// Add a job to the bool. Note this call will block if the underlying
|
|
|
|
// queue is full.
|
|
|
|
// Returns false if the queue is currently disabled.
|
|
|
|
bool
|
|
|
|
addJob(const Job& job);
|
|
|
|
bool
|
|
|
|
addJob(Job&& job);
|
|
|
|
|
|
|
|
// Try to add a job to the pool. If the queue is full, or the queue is
|
|
|
|
// disabled, return false.
|
|
|
|
// This call will not block.
|
|
|
|
bool
|
|
|
|
tryAddJob(const Job& job);
|
|
|
|
bool
|
|
|
|
tryAddJob(Job&& job);
|
|
|
|
|
|
|
|
// Wait until all current jobs are complete.
|
|
|
|
// If any jobs are submitted during this time, they **may** or **may not**
|
|
|
|
// run.
|
|
|
|
void
|
|
|
|
drain();
|
|
|
|
|
|
|
|
// Disable this pool, and cancel all pending jobs. After all currently
|
|
|
|
// running jobs are complete, join with the threads in the pool.
|
|
|
|
void
|
|
|
|
shutdown();
|
|
|
|
|
|
|
|
// Start this threadpool by spawning `threadCount()` threads.
|
|
|
|
bool
|
|
|
|
start();
|
|
|
|
|
|
|
|
// Disable queueing on this threadpool and wait until all pending jobs
|
|
|
|
// have finished.
|
|
|
|
void
|
|
|
|
stop();
|
|
|
|
|
|
|
|
bool
|
|
|
|
enabled() const;
|
|
|
|
|
|
|
|
bool
|
|
|
|
started() const;
|
|
|
|
|
|
|
|
size_t
|
|
|
|
activeThreadCount() const;
|
|
|
|
|
|
|
|
// Current number of queued jobs
|
|
|
|
size_t
|
|
|
|
jobCount() const;
|
|
|
|
|
|
|
|
// Number of threads passed in the constructor
|
|
|
|
size_t
|
|
|
|
threadCount() const;
|
|
|
|
|
|
|
|
// Number of threads currently started in the threadpool
|
|
|
|
size_t
|
|
|
|
startedThreadCount() const;
|
|
|
|
|
|
|
|
// Max number of queued jobs
|
|
|
|
size_t
|
|
|
|
capacity() const;
|
|
|
|
};
|
|
|
|
|
|
|
|
inline void
|
|
|
|
ThreadPool::disable()
|
|
|
|
{
|
|
|
|
m_queue.disable();
|
|
|
|
}
|
|
|
|
|
|
|
|
inline void
|
|
|
|
ThreadPool::enable()
|
|
|
|
{
|
|
|
|
m_queue.enable();
|
|
|
|
}
|
|
|
|
|
|
|
|
inline bool
|
|
|
|
ThreadPool::enabled() const
|
|
|
|
{
|
|
|
|
return m_queue.enabled();
|
|
|
|
}
|
|
|
|
|
|
|
|
inline size_t
|
|
|
|
ThreadPool::activeThreadCount() const
|
|
|
|
{
|
|
|
|
if(m_threads.size() == m_createdThreads)
|
|
|
|
{
|
|
|
|
return m_threads.size() - m_idleThreads.load(std::memory_order_relaxed);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
inline size_t
|
|
|
|
ThreadPool::threadCount() const
|
|
|
|
{
|
|
|
|
return m_threads.size();
|
|
|
|
}
|
|
|
|
|
|
|
|
inline size_t
|
|
|
|
ThreadPool::startedThreadCount() const
|
|
|
|
{
|
|
|
|
return m_createdThreads;
|
|
|
|
}
|
|
|
|
|
|
|
|
inline size_t
|
|
|
|
ThreadPool::jobCount() const
|
|
|
|
{
|
|
|
|
return m_queue.size();
|
|
|
|
}
|
|
|
|
|
|
|
|
inline size_t
|
|
|
|
ThreadPool::capacity() const
|
|
|
|
{
|
|
|
|
return m_queue.capacity();
|
|
|
|
}
|
|
|
|
} // namespace thread
|
|
|
|
} // namespace llarp
|
|
|
|
|
|
|
|
#endif
|