Suppose I have a QObject
and a blocking method (say, it's a library call that needs to fetch a lot of data from the network before returning).
class Foo : public QObject {
Bar* _bar;
public:
// non blocking call, emits stuffDone when done
void startStuff(int a, int b);
signals:
void stuffDone(int sum);
}
class Bar {
public:
// Blocking call
int doStuff(int a, b) {
for(int i=0; i<=100000000000; i++);
return a + b;
}
}
I'd like my Foo::startStuff
method to run doStuff
in the appropriate (separate) thread and trigger a stuffDone
signal upon completion.
startStuff
would have to return immediately.
Bar
can be a QObject if necessary, thus allowing for setting thread affinity via moveToThread
What is the simplest and most idiomatic ('Qt-like') way of doing so?
QtConcurrent::run
would probably be most idiomatic:
struct Bar {
// Blocks for 3 seconds
int doStuff(int a, b) {
QThread::sleep(3);
return a+b+42;
}
};
class Foo : public QObject {
Q_OBJECT
Bar _bar;
public:
// Non-blocking, emits stuffDone when done
void startStuff(int a, int b) {
QtConcurrent::run([a,b,this]{
auto result = _bar.doStuff(a,b);
emit stuffDone(result);
});
}
Q_SIGNAL void stuffDone(int sum);
};
Instead of using the custom Foo
class, you could also use a QFutureWatcher
, but IMHO it's more cumbersome as there's no signal that provides the result - you'd need to connect a functor that works on the result.
QSharedPointer<Bar> bar { new Bar };
auto watcher = new QFutureWatcher<int>;
connect(watcher, &QFutureWatcher::finished, watcher, [watcher, bar]{
watcher->deleteLater();
int result = watcher->result();
// use the result here
});
auto future = QtConcurrent::run(&Bar::doStuff, bar, 1, 2);
watcher->setFuture(future);
Note that the "long" addition loop is usually optimized out since it has no side effects and is thus dead code. If you want to simulate blocking, use QThread::[|m|u]sleep
.