C++ 如何使异步API与需要同步性的API保持一致?
这个问题源于我之前问过的一个问题C++ 如何使异步API与需要同步性的API保持一致?,c++,qt,asynchronous,synchronous,C++,Qt,Asynchronous,Synchronous,这个问题源于我之前问过的一个问题 简而言之,image provider抽象类需要实现一个方法,该方法通过参数“url”请求图像并返回图像。例如,单个方法请求并返回图像。但是Qt的QNetworkAccessManager类严格设计为异步使用,例如,您使用一种方法请求url,并通过连接到完成请求后发出的信号来拦截url。例如,它必须分为两个步骤进行分解,这就提出了一个问题:如何使用一个要分解的类来实现映像提供程序所需的单个方法(考虑到我用来强制同步的黑客导致了混乱)?一般的答案是:无法安全地完成
简而言之,image provider抽象类需要实现一个方法,该方法通过参数“url”请求图像并返回图像。例如,单个方法请求并返回图像。但是Qt的
QNetworkAccessManager
类严格设计为异步使用,例如,您使用一种方法请求url,并通过连接到完成请求后发出的信号来拦截url。例如,它必须分为两个步骤进行分解,这就提出了一个问题:如何使用一个要分解的类来实现映像提供程序所需的单个方法(考虑到我用来强制同步的黑客导致了混乱)?一般的答案是:无法安全地完成。虽然在特定的情况下,这是可以做到的,但它需要对所涉及的代码进行仔细的检查,并提供一些证据证明由于可重入性没有问题
至于同步类的使用,您只需要在requestXxxx
方法的实现中运行一个本地事件循环。如果它在专用线程中运行,那么可重入性问题就不是什么问题,因为您可以控制线程中活动的对象
由于QQuickImageProvider
的实现可以指定ForceAsynchronousImageLoading
标志,因此您的提供程序将在自己的线程中运行,并且可以安全地运行自己的消息循环
请注意,默认的QML映像提供程序将URI作为输入,并且非常乐意从web加载映像—因此在这种情况下您不必担心它
因此,即使您的自定义图像提供程序是完全不必要的,如果您要创建它,以下是您可能的做法:
class MyImageProvider : public QQuickImageProvider {
public:
MyImageProvider();
Flags flags() const { return ForceAsynchronousImageLoading; }
QImage requestImage(const QString & id, QSize * size, const QSize & requestedSize)
Q_DECL_OVERRIDE;
}
QImage MyImageProvider::requestImage(
const QString & id, QSize * size, const QSize & requestedSize)
{
QImage image;
QEventLoop loop;
QNetworkAccessManager mgr;
QObject::connect(&mgr, &QNetworkAccessManager::finished,
[&loop, size](QNetworkReply* reply) {
image.load(reply, "JPG");
if (size) *size = image.size();
loop.quit();
delete reply;
});
mgr.get(QNetworkRequest(QUrl(id)));
loop.exec();
return image;
}
您的意思是,在这种特殊情况下,
QEventLoop
默认情况下没有实例化自己的线程,而是在主线程中运行?@user3735658 aQEventLoop
没有实例化任何线程!!但是,由于您需要一个事件循环来运行异步网络访问管理器,并且您需要在执行requestXxxx
时运行该事件循环,因此您需要创建一个事件循环并exec()
它。因此,我还必须实例化一个线程,将对象移动到该线程,但仍然锁定该方法,直到事件循环完成(我怎样才能知道这是什么时候?)?目前尚不清楚如何解决该问题。@user3735658图像提供程序中存在的ForceAsynchronousImageLoading
标志使QML引擎创建一个工作线程,并在该线程中运行requestXxx
。线程实例化已为您完成。@user3735658除非在下面运行它,否则您永远不会知道它调试程序并亲自查看它崩溃的确切位置。不要问我们:)