为阻塞调用构造 signal/slot 包装器的正确方法是什么?
What's the proper way to construct a signal/slot wrapper to a blocking call?
假设我有一个 QObject
和一个阻塞方法(比如说,它是一个库调用,需要在 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
必须立即 return。
Bar
如有必要, 可以是 QObject,从而允许通过 moveToThread
设置线程关联
最简单和最惯用的 ('Qt-like') 方法是什么?
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);
};
除了使用自定义 Foo
class,您还可以使用 QFutureWatcher
,但恕我直言,它更麻烦,因为没有提供结果的信号 - 您需要连接一个作用于结果的函子。
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);
请注意,"long" 加法循环通常会被优化掉,因为它没有副作用,因此是死代码。如果要模拟阻塞,使用QThread::[|m|u]sleep
.
假设我有一个 QObject
和一个阻塞方法(比如说,它是一个库调用,需要在 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
必须立即 return。
Bar
如有必要, 可以是 QObject,从而允许通过 moveToThread
最简单和最惯用的 ('Qt-like') 方法是什么?
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);
};
除了使用自定义 Foo
class,您还可以使用 QFutureWatcher
,但恕我直言,它更麻烦,因为没有提供结果的信号 - 您需要连接一个作用于结果的函子。
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);
请注意,"long" 加法循环通常会被优化掉,因为它没有副作用,因此是死代码。如果要模拟阻塞,使用QThread::[|m|u]sleep
.