CThreadPool: Add cancellation support

This adds CThreadPool::cancelJob() and cancelJobs() which can cancel a set of
jobs synchronously. These functions only return when the job was successfully
cancelled.

It tries to cancel the jobs as quickly as possible, skipping any callbacks on
CJob that were not yet called. A job that is already running can use
CJob::wasCancelled() to check if it should quit.

Signed-off-by: Uli Schlachter <psychon@znc.in>
This commit is contained in:
Uli Schlachter
2014-08-06 15:15:57 +02:00
parent 6118ad5345
commit 1d67e87d90
3 changed files with 262 additions and 7 deletions
+38 -2
View File
@@ -216,6 +216,17 @@ private:
*/
class CJob {
public:
friend class CThreadPool;
enum EJobState {
READY,
RUNNING,
DONE,
CANCELLED
};
CJob() : m_eState(READY) {}
/// Destructor, always called from the main thread.
virtual ~CJob() {}
@@ -224,17 +235,26 @@ public:
/// This function is called from the main thread after runThread()
/// finishes. It can be used to handle the results from runThread()
/// without needing synchronization primitives.
/// without needing synchronization primitives.
virtual void runMain() = 0;
/// This can be used to check if the job was cancelled. For example,
/// runThread() can return early if this returns true.
bool wasCancelled() const;
private:
// Undefined copy constructor and assignment operator
CJob(const CJob&);
CJob& operator=(const CJob&);
// Synchronized via the thread pool's mutex! Do not access without that mutex!
EJobState m_eState;
};
class CThreadPool {
private:
friend class CJob;
CThreadPool();
~CThreadPool();
@@ -244,6 +264,16 @@ public:
/// Add a job to the thread pool and run it. The job will be deleted when done.
void addJob(CJob *job);
/// Cancel a job that was previously passed to addJob(). This *might*
/// mean that runThread() and/or runMain() will not be called on the job.
/// This function BLOCKS until the job finishes!
void cancelJob(CJob *job);
/// Cancel some jobs that were previously passed to addJob(). This *might*
/// mean that runThread() and/or runMain() will not be called on some of
/// the jobs. This function BLOCKS until all jobs finish!
void cancelJobs(const std::set<CJob *> &jobs);
int getReadFD() const {
return m_iJobPipe[0];
}
@@ -251,11 +281,14 @@ public:
void handlePipeReadable() const;
private:
void jobDone(const CJob* pJob) const;
void jobDone(CJob* pJob);
// Check if the calling thread is still needed, must be called with m_mutex held
bool threadNeeded() const;
CJob *getJobFromPipe() const;
void finishJob(CJob *) const;
void threadFunc();
static void *threadPoolFunc(void *arg) {
CThreadPool &pool = *reinterpret_cast<CThreadPool *>(arg);
@@ -269,6 +302,9 @@ private:
// condition variable for waiting idle threads
CConditionVariable m_cond;
// condition variable for reporting finished cancellation
CConditionVariable m_cancellationCond;
// when this is true, all threads should exit
bool m_done;