Job Queue
← Mandelbrot Example | ● | Threaded Image Conversion →
In the following we will outline another threading pattern: a job queue.
A job queue executes jobs one after another. There is not one thread for each job but one worker thread that works off all jobs.
First let’s define a base class for a job. It is derived from std::string to encode information about the job, e.g. a command line or file to work on. It also has a pure virtual execute() method that does the job:
{
public:
Job() : std::string() {}
Job(const std::string &s) : std::string(s) {}
virtual ~Job() {}
virtual int execute() = 0;
};
Now we define a job queue:
And now we define a worker class that maintains the job queue:
{
Q_OBJECT;
public:
//! default constructor
worker(QObject *parent=0)
: QThread(parent)
{
failure=0;
}
//! destructor
virtual ~worker()
{abort_jobs();}
void run_job(Job *job)
{
block_jobs();
jobs.push_back(job);
unblock_jobs();
start_jobs();
}
int finish_jobs()
{
wait4jobs();
return(failure);
}
protected:
virtual void block_jobs() {mutex.lock();}
virtual void unblock_jobs() {mutex.unlock();}
virtual void start_jobs()
{
if (!isRunning())
start(LowPriority); // calls run() in a new thread
}
virtual void wait4jobs() {wait();}
virtual void run()
{
int errorcode;
block_jobs();
failure=0;
while (!jobs.empty())
{
Job *job=jobs[0];
unblock_jobs();
errorcode=job->execute();
if (!errorcode)
emit finishedJob(*job);
else
{
emit failedJob(*job, errorcode);
failure++;
}
block_jobs();
jobs.erase(jobs.begin());
}
unblock_jobs();
}
private:
Jobs jobs;
int failure;
QMutex mutex;
signals:
void finishedJob(const std::string &job);
void failedJob(const std::string &job, int errorcode);
};