Given the recent discussion about multi-threading the following might be of interest: Request For Comments: KThread Why Threads? ============ Within KDE a level of parallelism is reached using two mechanisms: events and sub-processes. Up till now KDE has not made use of threads. There are some good reasons for this: 1. Threads are complex to use 2. Most activities can be handled in parallel using either events or sub-processes. 3. Thread implementations were not widely available in a portable fashion. The above not withstanding, there is an additional need for a finer grained paralellism within KDE which can be achieved with threads: * Processing operations which can take an unpredictable and/or unbounded amount of time. For these operations, events or sub-processes are often not well suited. The processing can theoretically be split in small processing-units and each processing-unit can be handled during one event. This approach is taken in the HTML Widget. It is however, not always possible to split a processing task into smaller tasks. In the case of the HTML widget, starting and stopping the processing of a chunk of HTML code can actually take longer than the processing of the chunk itself. Another example could be the loading a of large JPG image. Although technically possible to do this in small chunks, the library used for handling JPG does not foresee in this. The other approach to achieve paralellism is to use sub-processes. The best example within KDE for this are our IO-slaves. A seperate process is however unsuitable for tasks which require an intimate interaction with data-structures in the parent process, or who produce large quantities of data, e.g. image/multi-media operations. I think it's therefor safe to conclude that there is a need for a finer grained form of paralellism which can be achieved with threads. Goals of KThread ================ I stated three reasons why threads haven't been used widely within KDE. I have shown that the second reason, "Most activities can be handled in parallel using either events or sub-processes.", might be valid, but leaves a significant group of activities out in the cold. With KThread I want to offer finer grained paralellism which addresses the other two points: * KThread should make threading easy. * KThread should take care of portability issues. Interface of KThread ==================== I would like to make the following proposal for a KThread implementation. [An explanation and some examples follow below: NOT YET FINISHED] class KThread { public: KThread(KThreadWorker *worker); /** * Returns whether the thread is still active */ bool isRunning(); /** * Terminates thread on the first sequence point. * (Almost the same as "suspend(); kill();") */ void cancel(); /** * Terminates a thread unconditionally. * You better know what you are doing. */ void kill(); /** * Suspends thread when it reaches the next sequence point. */ void suspend(); /** * Resumes the thread after it has been suspended. */ void resume(); signals: /** * Signal indicating the "progress scale". */ void maxProgress(int _maxProgress); /** * Signal indicating progress */ void progress(int _progress); /** * Signal containing some info message */ void info(QString infoMsg); /** * Signal indicating the thread has finished. (See also isRunning()) */ void finished(); } class KThreadWorker { /** * Constructor. * * The constructor is called from the main-thread. */ KThreadWorker(); /** * Destructor. * * The destructor is called from the main-thread. */ virtual ~KThreadWorker(); /** * Function which does the actual work. * Returning from this function terminates the thread. */ virtual void exec() { }; /** * Function which gets called before a thread is canceled. * This function gets called in the thread itself. * * Either 'finished()' or 'canceled()' is called but * never both of them. */ virtual void canceled() { }; /** * Function which gets called before a thread ends. * This function gets called in the thread itself. * * Either 'finished()' or 'canceled()' is called but * never both of them. */ virtual void finsished() { }; /** * Function who indicates a sequence point. * The main-thread can suspend() the thread at this point. * Normally the object should make sure to be in * a defined state when entering this state. * * This function returns very fast when no suspend() is * pending. */ void sequencePoint(); /** * Sends a maxProgress signal to the main-thread. * * The thread gets suspended until the signal has been * handled by the main-thread. * * (Synchronizes with main-thread) **/ void maxProgress(int _maxProgress); /** * Sends a progress signal to the main-thread. * * The thread gets suspended until the signal has been * handled by the main-thread. * * (Synchronizes with main-thread) **/ void progress(int _progress); /** * Sends a info signal to the main-thread. * * The thread gets suspended until the signal has been * handled by the main-thread. * * (Synchronizes with main-thread) **/ void info(QString infoMsg); /** * Sends an event in the application main-loop. * * The thread gets suspended until the event has been * handled by the main-thread. * * (Synchronizes with main-thread) **/ void sendEvent(QObject *receiver, QEvent *ev); }