Concurrent Run▲
The QtConcurrent::run() function runs a function in a separate thread. The return value of the function is made available through the QFuture API.
QtConcurrent::run() is an overloaded method. You can think of these overloads as slightly different modes. In basic mode, the function passed to QtConcurrent::run() is able to report merely a single computation result to its caller. In run with promise mode, the function passed to QtConcurrent::run() can make use of the additional QPromise API, which enables multiple result reporting, progress reporting, suspending the computation when requested by the caller, or stopping the computation on the caller's demand.
This function is a part of the Qt Concurrent framework.
Concurrent Run (basic mode)▲
The function passed to QtConcurrent::run() may report the result through its return value.
Running a Function in a Separate Thread▲
To run a function in another thread, use QtConcurrent::run():
extern
void
aFunction();
QFuture&
lt;void
&
gt; future =
QtConcurrent::
run(aFunction);
This will run aFunction in a separate thread obtained from the default QThreadPool. You can use the QFuture and QFutureWatcher classes to monitor the status of the function.
To use a dedicated thread pool, you can pass the QThreadPool as the first argument:
extern
void
aFunction();
QThreadPool pool;
QFuture&
lt;void
&
gt; future =
QtConcurrent::
run(&
amp;pool, aFunction);
Passing Arguments to the Function▲
Passing arguments to the function is done by adding them to the QtConcurrent::run() call immediately after the function name. For example:
extern
void
aFunctionWithArguments(int
arg1, double
arg2, const
QString &
amp;string);
int
integer =
...;
double
floatingPoint =
...;
QString string =
...;
QFuture&
lt;void
&
gt; future =
QtConcurrent::
run(aFunctionWithArguments, integer, floatingPoint, string);
A copy of each argument is made at the point where QtConcurrent::run() is called, and these values are passed to the thread when it begins executing the function. Changes made to the arguments after calling QtConcurrent::run() are not visible to the thread.
Note that QtConcurrent::run does not support calling overloaded functions directly. For example, the code below won't compile:
void
foo(int
arg);
void
foo(int
arg1, int
arg2);
...
QFuture&
lt;void
&
gt; future =
QtConcurrent::
run(foo, 42
);
The easiest workaround is to call the overloaded function through lambda:
QFuture&
lt;void
&
gt; future =
QtConcurrent::
run([] {
foo(42
); }
);
Or you can tell the compiler which overload to choose by using a static_cast:
QFuture&
lt;void
&
gt; future =
QtConcurrent::
run(static_cast
&
lt;void
(*
)(int
)&
gt;(foo), 42
);
Or qOverload:
QFuture&
lt;void
&
gt; future =
QtConcurrent::
run(qOverload&
lt;int
&
gt;(foo), 42
);
Returning Values from the Function▲
Any return value from the function is available via QFuture:
extern
QString functionReturningAString();
QFuture&
lt;QString&
gt; future =
QtConcurrent::
run(functionReturningAString);
...
QString result =
future.result();
As documented above, passing arguments is done like this:
extern
QString someFunction(const
QByteArray &
amp;input);
QByteArray bytearray =
...;
QFuture&
lt;QString&
gt; future =
QtConcurrent::
run(someFunction, bytearray);
...
QString result =
future.result();
Note that the QFuture::result() function blocks and waits for the result to become available. Use QFutureWatcher to get notification when the function has finished execution and the result is available.
Additional API Features▲
Using Member Functions▲
QtConcurrent::run() also accepts pointers to member functions. The first argument must be either a const reference or a pointer to an instance of the class. Passing by const reference is useful when calling const member functions; passing by pointer is useful for calling non-const member functions that modify the instance.
For example, calling QByteArray::split() (a const member function) in a separate thread is done like this:
// call 'QList<QByteArray> QByteArray::split(char sep) const' in a separate thread
QByteArray bytearray =
"hello world"
;
QFuture&
lt;QList&
lt;QByteArray&
gt; &
gt; future =
QtConcurrent::
run(&
amp;QByteArray::
split, bytearray, ' '
);
...
QList&
lt;QByteArray&
gt; result =
future.result();
Calling a non-const member function is done like this:
// call 'void QImage::invertPixels(InvertMode mode)' in a separate thread
QImage image =
...;
QFuture&
lt;void
&
gt; future =
QtConcurrent::
run(&
amp;QImage::
invertPixels, &
amp;image, QImage::
InvertRgba);
...
future.waitForFinished();
// At this point, the pixels in 'image' have been inverted
Using Lambda Functions▲
Calling a lambda function is done like this:
QFuture&
lt;void
&
gt; future =
QtConcurrent::
run([=
]() {
// Code in this block will run in another thread
}
);
...
Calling a function modifies an object passed by reference is done like this:
static
void
addOne(int
&
amp;n) {
++
n; }
...
int
n =
42
;
QtConcurrent::
run(&
amp;addOne, std::
ref(n)).waitForFinished(); // n == 43
Using callable object is done like this:
struct
TestClass
{
void
operator
()(int
s1) {
s =
s1; }
int
s =
42
;
}
;
...
TestClass o;
// Modify original object
QtConcurrent::
run(std::
ref(o), 15
).waitForFinished(); // o.s == 15
// Modify a copy of the original object
QtConcurrent::
run(o, 42
).waitForFinished(); // o.s == 15
// Use a temporary object
QtConcurrent::
run(TestClass(), 42
).waitForFinished();
// Ill-formed
QtConcurrent::
run(&
amp;o, 42
).waitForFinished(); // compilation error
Concurrent Run With Promise▲
The Run With Promise mode enables more control for the running task compared to basic mode of QtConcurrent::run(). It allows progress reporting of the running task, reporting multiple results, suspending the execution if it was requested, or canceling the task on caller's demand.
The mandatory QPromise argument▲
The function passed to QtConcurrent::run() in Run With Promise mode is expected to have an additional argument of QPromise<T> & type, where T is the type of the computation result (it should match the type T of QFuture<T> returned by QtConcurrent::run()), like e.g.:
extern
void
aFunction(QPromise&
lt;void
&
gt; &
amp;promise);
QFuture&
lt;void
&
gt; future =
QtConcurrent::
run(aFunction);
The promise argument is instantiated inside the QtConcurrent::run() function, and its reference is passed to the invoked aFunction, so the user doesn't need to instantiate it, nor pass it explicitly when calling QtConcurrent::run() in this mode.
The additional argument of QPromise type always needs to appear as a first argument on function's arguments list, like:
extern
void
aFunction(QPromise&
lt;void
&
gt; &
amp;promise, int
arg1, const
QString &
amp;arg2);
int
integer =
...;
QString string =
...;
QFuture&
lt;void
&
gt; future =
QtConcurrent::
run(aFunction, integer, string);
Reporting results▲
In contrast to basic mode of QtConcurrent::run(), the function passed to QtConcurrent::run() in Run With Promise mode is expected to always return void type. Result reporting is done through the additional argument of QPromise type. It also enables multiple result reporting, like:
void
helloWorldFunction(QPromise&
lt;QString&
gt; &
amp;promise)
{
promise.addResult("Hello"
);
promise.addResult("world"
);
}
QFuture&
lt;QString&
gt; future =
QtConcurrent::
run(helloWorldFunction);
...
QList&
lt;QString&
gt; results =
future.results();
There's no need to call QPromise::start() and QPromise::finish() to indicate the beginning and the end of computation (like you would normally do when using QPromise). QtConcurrent::run() will always call them before starting and after finishing the execution.
Suspending and canceling the execution▲
The QPromise API also enables suspending and canceling the computation, if requested:
void
aFunction(QPromise&
lt;int
&
gt; &
amp;promise)
{
for
(int
i =
0
; i &
lt; 100
; ++
i) {
promise.suspendIfRequested();
if
(promise.isCanceled())
return
;
// computes the next result, may be time consuming like 1 second
const
int
res =
... ;
promise.addResult(res);
}
}
QFuture&
lt;int
&
gt; future =
QtConcurrent::
run(aFunction);
... // user pressed a pause button after 10 seconds
future.suspend();
... // user pressed a resume button after 10 seconds
future.resume();
... // user pressed a cancel button after 10 seconds
future.cancel();
The call to future.suspend() requests the running task to hold its execution. After calling this method, the running task will suspend after the next call to promise.suspendIfRequested() in its iteration loop. In this case the running task will block on a call to promise.suspendIfRequested(). The blocked call will unblock after the future.resume() is called. Note, that internally suspendIfRequested() uses wait condition in order to unblock, so the running thread goes into an idle state instead of wasting its resources when blocked in order to periodically check if the resume request came from the caller's thread.
The call to future.cancel() from the last line causes that the next call to promise.isCanceled() will return true and aFunction will return immediately without any further result reporting.
There's no need to call QPromise::finish() to stop the computation after the cancellation (like you would normally do when using QPromise). QtConcurrent::run() will always call it after finishing the execution.
Progress reporting▲
It's also possible to report the progress of a task independently of result reporting, like:
void
aFunction(QPromise&
lt;int
&
gt; &
amp;promise)
{
promise.setProgressRange(0
, 100
);
int
result =
0
;
for
(int
i =
0
; i &
lt; 100
; ++
i) {
// computes some part of the task
const
int
part =
... ;
result +=
part;
promise.setProgressValue(i);
}
promise.addResult(result);
}
QFutureWatcher&
lt;int
&
gt; watcher;
QObject::
connect(&
amp;watcher, &
amp;QFutureWatcher::
progressValueChanged, [](int
progress){
... ; // update GUI with a progress
qDebug() &
lt;&
lt; "current progress:"
&
lt;&
lt; progress;
}
);
watcher.setFuture(QtConcurrent::
run(aFunction));
The caller installs the QFutureWatcher for the QFuture returned by QtConcurrent::run() in order to connect to its progressValueChanged() signal and update e.g. the graphical user interface accordingly.
Invoking functions with overloaded operator()()▲
By default, QtConcurrent::run() doesn't support functors with overloaded operator()() in Run With Promise mode. In case of overloaded functors the user needs to explicitly specify the result type as a template parameter passed to QtConcurrent::run(), like:
struct
Functor {
void
operator
()(QPromise&
lt;int
&
gt; &
amp;) {
}
void
operator
()(QPromise&
lt;double
&
gt; &
amp;) {
}
}
;
Functor f;
run&
lt;double
&
gt;(f); // this will select the 2nd overload
// run(f); // error, both candidate overloads potentially match