【问题标题】:How to conform an asynchronous API to an API that requires synchronicity?如何使异步 API 符合需要同步的 API?
【发布时间】:2014-09-20 01:31:47
【问题描述】:

这个问题源于我之前问过的question

简而言之,图像提供者抽象类需要实现一种通过参数“url”请求图像并返回图像的方法。例如。单个方法请求并返回图像。但是 Qt 的 QNetworkAccessManager 类是严格为异步使用而设计的,例如您以一种方法请求 url 并通过连接到请求完成时发出的信号来拦截它。例如。它必须分两步分解,这就提出了一个问题,一个问题是如何实现图像提供程序所需的单个方法和一个打算分解的类(考虑到我用来强制它同步的黑客行为导致一团糟)?

【问题讨论】:

    标签: c++ qt asynchronous synchronous


    【解决方案1】:

    一般的答案是:它不能安全地完成。虽然在特定情况下可以做到,但需要对所涉及的代码进行仔细审查,并提供一些证明没有由于重入导致的问题。

    至于同步类的使用,你只需要在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 QEventLoop 没有实例化任何线程!!但是,由于您需要一个事件循环来运行异步网络访问管理器,并且您需要该事件循环来运行 while requestXxxx 执行,因此您需要创建一个并 exec() 它。
    • 所以我还必须实例化一个线程,将对象移动到该线程但仍然锁定该方法,直到事件循环完成(我怎么知道那是什么时候?)?目前还不清楚如何解决这个问题。
    • @user3735658 图像提供程序中ForceAsynchronousImageLoading 标志的存在使QML 引擎创建一个工作线程并在该线程中运行requestXxx为您完成线程实例化。
    • @user3735658 你永远不会知道除非你在调试器下运行它并亲自看看它到底在哪里崩溃了。不要问我们:)
    猜你喜欢
    • 1970-01-01
    • 2012-05-23
    • 1970-01-01
    • 2015-11-21
    • 2011-01-09
    • 2017-05-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多