为阻塞调用构造信号/时隙包装器的正确方法是什么? [英] What's the proper way to construct a signal/slot wrapper to a blocking call?
问题描述
假设我有一个QObject
和一个阻塞方法(例如,这是一个库调用,需要在返回之前从网络中获取大量数据).
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;
}
}
我希望我的Foo::startStuff
方法在适当的(单独的)线程中运行doStuff
,并在完成时触发stuffDone
信号.
startStuff
必须立即返回.
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
可以是QObject,从而允许通过moveToThread
Bar
can be a QObject if necessary, thus allowing for setting thread affinity via moveToThread
最简单,最惯用的"Qt类"方法是什么?
What is the simplest and most idiomatic ('Qt-like') way of doing so?
推荐答案
QtConcurrent::run
可能是最惯用的:
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);
};
您也可以使用QFutureWatcher
,而不是使用自定义的Foo
类,但是恕我直言,这比较麻烦,因为没有提供结果的信号-您需要连接一个对结果起作用的函子.
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);
请注意,长"加法循环通常被优化,因为它没有副作用,因此是无效代码.如果要模拟阻止,请使用QThread::[|m|u]sleep
.
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
.
这篇关于为阻塞调用构造信号/时隙包装器的正确方法是什么?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!