File indexing completed on 2024-04-28 04:01:23

0001 /* -*- C++ -*-
0002     This file declares the Job class.
0003 
0004     SPDX-FileCopyrightText: 2004-2013 Mirko Boehm <mirko@kde.org>
0005 
0006     SPDX-License-Identifier: LGPL-2.0-or-later
0007 
0008     $Id: Job.h 32 2005-08-17 08:38:01Z mirko $
0009 */
0010 
0011 #ifndef THREADWEAVER_JOB_H
0012 #define THREADWEAVER_JOB_H
0013 
0014 #include "jobinterface.h"
0015 #include "jobpointer.h"
0016 #include "threadweaver_export.h"
0017 
0018 class QMutex;
0019 class QWaitCondition;
0020 
0021 namespace ThreadWeaver
0022 {
0023 namespace Private
0024 {
0025 class Job_Private;
0026 }
0027 
0028 class Thread;
0029 class QueuePolicy;
0030 class QueueAPI;
0031 class Executor;
0032 
0033 /** @brief A Job is a simple abstraction of an action that is to be executed in a thread context.
0034  *
0035  * It is essential for the ThreadWeaver library that as a kind of convention, the different creators of Job objects do not touch
0036  * the protected data members of the Job until somehow notified by the Job.
0037  *
0038  * Jobs may not be executed twice. Create two different objects to perform two consecutive or parallel runs.
0039  * (Note: this rule is being reconsidered.)
0040  *
0041  * Jobs may declare dependencies. If Job B depends on Job A, B may not be executed before A is finished. To learn about
0042  * dependencies, see DependencyPolicy.
0043  *
0044  * Job objects do not inherit QObject. To connect to signals when jobs are started or finished, see QObjectDecorator.
0045  */
0046 class THREADWEAVER_EXPORT Job : public JobInterface
0047 {
0048 public:
0049     /** Construct a Job. */
0050     Job();
0051     Job(Private::Job_Private *d);
0052 
0053     /** Destructor. */
0054     ~Job() override;
0055 
0056     /** Perform the job. The thread in which this job is executed is given as a parameter.
0057      *
0058      * Do not overload this method to create your own Job implementation, overload run().
0059      * Whenever the currently executed job is communicated to the outside world, use the supplied job pointer
0060      * to keep the reference count correct.
0061      *
0062      * job is the Job that the queue is executing. It is not necessarily equal to this. For example, Jobs that are
0063      * decorated expose the decorator's address, not the address of the decorated object.
0064      */
0065     void execute(const JobPointer &job, Thread *) override;
0066 
0067     /** Perform the job synchronously in the current thread. */
0068     void blockingExecute() override;
0069 
0070     /** Set the Executor object that is supposed to run the job.
0071      *
0072      * Returns the previously set executor. The executor can never be unset. If zero is passed in as the new executor, the Job
0073      * will internally reset to a default executor that only invokes run().
0074      */
0075     Executor *setExecutor(Executor *executor) override;
0076 
0077     /** Returns the executor currently set on the Job. */
0078     Executor *executor() const override;
0079 
0080     /** The queueing priority of the job.
0081      * Jobs will be sorted by their queueing priority when enqueued. A higher queueing priority will place the job in front of all
0082      * lower-priority jobs in the queue.
0083      *
0084      * Note: A higher or lower priority does not influence queue policies. For example, a high-priority job that has an unresolved
0085      * dependency will not be executed, which means an available lower-priority job will take precedence.
0086      *
0087      * The default implementation returns zero. Only if this method is overloaded for some job classes, priorities will influence
0088      * the execution order of jobs. */
0089     int priority() const override;
0090 
0091     /** @brief Set the status of the Job.
0092      *
0093      * Do not call this method unless you know what you are doing, please :-) */
0094     void setStatus(Status) override;
0095 
0096     /** @brief The status of the job.
0097      *
0098      * The status will be changed to Status_Success if the run() method exits normally.
0099      */
0100     Status status() const override;
0101 
0102     /** Return whether the Job finished successfully or not.
0103      * The default implementation simply returns true. Overload in derived classes if the derived Job class can fail.
0104      *
0105      * If a job fails (success() returns false), it will *NOT* resolve its dependencies when it finishes. This will make sure that
0106      * Jobs that depend on the failed job will not be started.
0107      *
0108      * There is an important gotcha: When a Job object it deleted, it will always resolve its dependencies. If dependent jobs should
0109      * not be executed after a failure, it is important to dequeue those before deleting the failed Job. A Sequence may be
0110      * helpful for that purpose.
0111      */
0112     bool success() const override;
0113 
0114     /** Abort the execution of the job.
0115      *
0116      * Call this method to ask the Job to abort if it is currently executed. Default implementation of the method sets a flag
0117      * causing `shouldAbort()` return true. You can reimplement this method to actually initiate an abort action.
0118      *
0119      * This method is supposed to return immediately, not after the abort has completed. It requests the abort, the Job has to act on
0120      * the request. */
0121     void requestAbort() override;
0122 
0123     /** @brief Whether Job should abort itself
0124      *
0125      * It will return true if `requestAbort()` was invoked before
0126      * but it's up to the job implementation itself to honor it
0127      * and some implementations might not actually abort (ie. unabortable job).
0128      *
0129      * @threadsafe
0130      *
0131      * @since 6.0
0132      */
0133     bool shouldAbort() const;
0134 
0135     /** The job is about to be added to the weaver's job queue.
0136      *
0137      * The job will be added right after this method finished. The default implementation does nothing. Use this method to, for
0138      * example, queue sub-operations as jobs before the job itself is queued.
0139      *
0140      * Note: When this method is called, the associated Weaver object's thread holds a lock on the weaver's queue. Therefore, it
0141      * is save to assume that recursive queueing is atomic from the queues perspective.
0142      *
0143      * @param api the QueueAPI object the job will be queued in */
0144     void aboutToBeQueued(QueueAPI *api) override;
0145 
0146     /** Called from aboutToBeQueued() while the mutex is being held. */
0147     void aboutToBeQueued_locked(QueueAPI *api) override;
0148 
0149     /** This Job is about the be dequeued from the weaver's job queue.
0150      *
0151      * The job will be removed from the queue right after this method returns. Use this method to dequeue, if necessary,
0152      * sub-operations (jobs) that this job has enqueued.
0153      *
0154      * Note: When this method is called, the associated Weaver object's thread does hold a lock on the weaver's queue.
0155      * Note: The default implementation does nothing.
0156      *
0157      * @param weaver the Weaver object from which the job will be dequeued */
0158     void aboutToBeDequeued(QueueAPI *api) override;
0159 
0160     /** Called from aboutToBeDequeued() while the mutex is being held. */
0161     void aboutToBeDequeued_locked(QueueAPI *api) override;
0162 
0163     /** Returns true if the jobs's execute method finished. */
0164     bool isFinished() const override;
0165 
0166     /** Add handler that will be invoked once job has finished
0167      *
0168      * @since 6.0
0169      */
0170     void onFinish(const std::function<void(const JobInterface &job)> &lambda);
0171 
0172     /** Assign a queue policy.
0173      *
0174      * Queue Policies customize the queueing (running) behaviour of sets of jobs. Examples for queue policies are dependencies
0175      * and resource restrictions. Every queue policy object can only be assigned once to a job, multiple assignments will be
0176      * IGNORED. */
0177     void assignQueuePolicy(QueuePolicy *) override;
0178 
0179     /** Remove a queue policy from this job. */
0180     void removeQueuePolicy(QueuePolicy *) override;
0181 
0182     /** @brief Return the queue policies assigned to this Job. */
0183     QList<QueuePolicy *> queuePolicies() const override;
0184 
0185     /** The mutex used to protect this job. */
0186     QMutex *mutex() const override;
0187 
0188 private:
0189     Private::Job_Private *d_;
0190 
0191 protected:
0192     Private::Job_Private *d();
0193     const Private::Job_Private *d() const;
0194 
0195     friend class Executor;
0196     /** The method that actually performs the job.
0197      *
0198      * It is called from execute(). This method is the one to overload it with the job's task.
0199      *
0200      * The Job will be executed in the specified thread. thread may be zero, indicating that the job is being executed some
0201      * other way (for example, synchronously by some other job). self specifies the job as the queue sees it. Whenever publishing
0202      * information about the job to the outside world, for example by emitting signals, use self, not this. self is the reference
0203      * counted object handled by the queue. Using it as signal parameters will amongst other things prevent thejob from being
0204      * memory managed and deleted.
0205      */
0206     virtual void run(JobPointer self, Thread *thread) override = 0;
0207 
0208     /** @brief Perform standard tasks before starting the execution of a job.
0209      *
0210      * The default implementation is empty.
0211      * job is the Job that the queue is executing. It is not necessarily equal to this. For example, Jobs that are
0212      * decorated expose the decorator's address, not the address of the decorated object. */
0213     void defaultBegin(const JobPointer &job, Thread *thread) override;
0214 
0215     /** @brief Perform standard task after the execution of a job.
0216      *
0217      * The default implementation is empty.
0218      * job is the Job that the queue is executing. It is not necessarily equal to this. For example, Jobs that are
0219      * decorated expose the decorator's address, not the address of the decorated object. */
0220     void defaultEnd(const JobPointer &job, Thread *thread) override;
0221 };
0222 
0223 }
0224 
0225 #endif // THREADWEAVER_JOB_H