首页 > 解决方案 > 使用 VS2019 构建时使用 Qt5qml 导致应用程序崩溃

问题描述

我有一个用VS2013Qt编译的应用程序5.9.6,它工作正常。现在我想升级 Qt 版本5.15.2并用 . 编译它VS2019。构建成功,我可以运行应用程序,但它总是在Qt5Qml模块处崩溃。 在此处输入图像描述

我调试了很长时间,但仍然不知道为什么。也许5.15.2与 VS2019 不完全兼容?

2020 年 4 月 20 日更新:我有一门课叫ExpressionEvaluator

class ExpressionEvaluator
{
    public:
        ExpressionEvaluator();
        virtual ~ExpressionEvaluator();

        bool evaluate(const QString &expression, const QVariantMap &values);

    protected:
        class ExpressionEvaluatorPrivate *d_ptr;
        Q_DECLARE_PRIVATE(ExpressionEvaluator);
        int gcCounter;
};

这是和的ExpressionEvaluatorPrivate定义ExpressionEvaluator

class ExpressionEvaluatorPrivate
{
    public:
        QJSEngine engine;
        QMutex mutex;
};

ExpressionEvaluator::ExpressionEvaluator()
    : d_ptr(new ExpressionEvaluatorPrivate()),
      gcCounter(0)
{}

ExpressionEvaluator::~ExpressionEvaluator()
{
    Q_D(ExpressionEvaluator);
    d->engine.collectGarbage();

    delete d_ptr;
}

bool ExpressionEvaluator::evaluate(const QString &expression, const QVariantMap &values)
{
    Q_D(ExpressionEvaluator);

    QMutexLocker locker(&d->mutex);
    // CRASH HERE
    for (auto it = values.begin(); it != values.end(); ++it) {
        d->engine.globalObject().setProperty(it.key(), d->engine.toScriptValue(it.value())); // <---CRASH HERE
    }

    QJSValue qjsValue = d->engine.evaluate(expression);

    bool ok = qjsValue.toBool();

    if (++gcCounter >= GC_CALL_LIMIT) {
        d->engine.collectGarbage();
        gcCounter = 0;
    }

    for (auto it = values.begin(); it != values.end(); ++it) {
        d->engine.globalObject().deleteProperty(it.key());
    }

    return ok;
}

标签: c++qtvisual-studio-2019

解决方案


经过很长时间的调试,这种痛苦。我终于找到了解决方案。(但我不清楚它为什么起作用:))。我只想在这里发布我的答案,这样如果有人像我一样遇到这个问题,可以找到解决方案。

如您所见,我有一个名为 的函数ExpressionEvaluator::evaluate,该函数将涉及多线程。Qt 一切正常,5.9.6但是当我升级到 Qt 时5.15.2,应用程序经常崩溃,堆栈跟踪指向周围QJsEngine的行d->engine.globalObject() 对于我的研究,也许这是问题所在:

  • QJsEngine有一个调用gc垃圾收集的函数
  • gc将与拥有引擎的线程一起运行。
  • 每当另一个线程尝试访问globalObject()或任何函数(如evaluate())时QJsEngine,如果gc同时调用 and if => crash

是的,就像我之前说的,我并不真正理解这个问题,但是有了这个猜测,我能够创建一个解决方案并且它有效!

这是我的解决方案:

  • 我创建了另一个线程(事件循环线程)QJsEngine并将住在那个线程中(它的所有功能也将在这个线程上执行)
  • 当另一个线程被调用evaluate()时,它将发出一个信号并且该信号连接到插槽(插槽将完成工作 - 当然,这个插槽仅在一个线程中执行)
  • 该解决方案确保:gc所有函数都将在同一个线程上执行。

P / s:对不起,如果我的解释很难理解,但这个问题有点具体,它坚持我的应用程序,所以这是我能做的最好的。但是总结一下:make sure all the function of QJsEngine is called in the same thread


推荐阅读