使用 VS2019 构建时,Qt5qml 应用程序崩溃
Application crash with Qt5qml when building with VS2019
我有一个用 VS2013
和 Qt 5.9.6
编译的应用程序,它工作正常。现在我想升级Qt版本到5.15.2
并用VS2019
编译它。构建成功,我可以运行应用程序但它总是在Qt5Qml
模块崩溃.
调试了很久,还是不知道为什么。也许5.15.2
与VS2019不完全兼容?
2020 年 4 月 20 日更新:
我有一个 class 叫做 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;
}
经过很长时间的调试,这让人头疼。我终于找到了解决方案。 (但我不清楚它为什么有效 :))。我只想post在这里回答我的问题,所以如果有人像我一样遇到这个问题可以找到解决方案。
如你所见,我有一个函数叫ExpressionEvaluator::evaluate
,这个函数会被多线程涉及到。使用 Qt 5.9.6
一切正常,但是当我升级到 Qt 5.15.2
时,应用程序经常崩溃并且堆栈跟踪指向 QJsEngine
附近的行 d->engine.globalObject()
对于我的研究,也许这就是问题所在:
QJsEngine
有一个名为 gc
的函数用于垃圾收集
gc
将 运行 拥有引擎的线程。
- 每当另一个线程正在尝试访问
globalObject()
或 QJsEngine
的任何函数(如 evaluate()
)并且如果同时调用 gc
=> 崩溃
是的,正如我之前所说,我并不真正理解这个问题,但根据这个猜测,我能够创建一个解决方案并且它有效!
这是我的解决方案:
- 我创建了另一个线程(事件循环线程),
QJsEngine
将在该线程中运行(同时它的所有功能都将在该线程中执行)
- 当另一个线程调用时
evaluate()
它将发出一个信号,并且该信号连接到插槽(插槽将完成工作 - 当然,该插槽仅在一个线程中执行)
- 此解决方案确保:
gc
所有函数都将在同一个线程上执行。
P/s:抱歉,如果我的解释难以理解,但这个问题有点具体,并且坚持我的应用程序,所以这是我能做的最好的。但对于摘要:make sure all the function of QJsEngine is called in the same thread
我有一个用 VS2013
和 Qt 5.9.6
编译的应用程序,它工作正常。现在我想升级Qt版本到5.15.2
并用VS2019
编译它。构建成功,我可以运行应用程序但它总是在Qt5Qml
模块崩溃.
调试了很久,还是不知道为什么。也许5.15.2
与VS2019不完全兼容?
2020 年 4 月 20 日更新:
我有一个 class 叫做 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;
}
经过很长时间的调试,这让人头疼。我终于找到了解决方案。 (但我不清楚它为什么有效 :))。我只想post在这里回答我的问题,所以如果有人像我一样遇到这个问题可以找到解决方案。
如你所见,我有一个函数叫ExpressionEvaluator::evaluate
,这个函数会被多线程涉及到。使用 Qt 5.9.6
一切正常,但是当我升级到 Qt 5.15.2
时,应用程序经常崩溃并且堆栈跟踪指向 QJsEngine
附近的行 d->engine.globalObject()
对于我的研究,也许这就是问题所在:
QJsEngine
有一个名为gc
的函数用于垃圾收集gc
将 运行 拥有引擎的线程。- 每当另一个线程正在尝试访问
globalObject()
或QJsEngine
的任何函数(如evaluate()
)并且如果同时调用gc
=> 崩溃
是的,正如我之前所说,我并不真正理解这个问题,但根据这个猜测,我能够创建一个解决方案并且它有效!
这是我的解决方案:
- 我创建了另一个线程(事件循环线程),
QJsEngine
将在该线程中运行(同时它的所有功能都将在该线程中执行) - 当另一个线程调用时
evaluate()
它将发出一个信号,并且该信号连接到插槽(插槽将完成工作 - 当然,该插槽仅在一个线程中执行) - 此解决方案确保:
gc
所有函数都将在同一个线程上执行。
P/s:抱歉,如果我的解释难以理解,但这个问题有点具体,并且坚持我的应用程序,所以这是我能做的最好的。但对于摘要:make sure all the function of QJsEngine is called in the same thread