In a C++/Qt program I need to run a few asynchronous tasks with "done" signals (for example network downloads, QProcess
, etc.) in sequence, each after the last finishes.
The only ways I can think of are to have a separate state class for each step (extremely verbose, like having a separate class for each line in a synchronous program), or to have one big class with a state enum and fields to hold all possible objects needed for the different steps (inflexible, difficult to maintain). Are there any good solutions for this? It seems like it should be a common problem, but I'm having trouble finding anything.
How about using
QRunnable
andQQueue
?QRunnable
is a runnable object. You inherit your class from it and reimplement theQRunnable::run()
method which will do the single asynchronous job (for example, download a file).QQueue
is a simple container which implements the "first in, first out" (FIFO). You may use any other container which fits your needs –QList
,QStack
, etc.General implementation:
Create a
done()
signal in you runnable object and emit it at the end of itsrun()
method. To query a new task, simply push your newQRunnable
object to the container and connect thedone()
signal to some slot which willdequeue
and run (asynchronously) a single task. Asynchronous run can be achieved using theQtConcurrent::run
, for example.You can also use
QRunnable
with theQThreadPool
and manually set the limit of concurrent tasks. Here you can read more about Qt multithreading technologies.There are many ways of doing it. One basic pattern is to connect functors to the
done()
signals:We can factor out the knowledge about the
done
signal of a particular class:If there are particular behaviors that are common on a class, or a pair of them, you can factor them out as well. The traits classes help prevent the combinatorial explosion due to multiple possible pairings:
You can also leverage the state machine system in a similarly declarative fashion.