我通过创建派生的QThread类使我的应用程序可编写脚本,我在其中添加了多个QObject类,以便通过命令行访问它们的函数。
void commandLine::addObject(QObject *obj, QString name)
{
QScriptValue sv = m_scriptEngine.newQObject(obj);
m_scriptEngine.globalObject().setProperty(name, sv);
qObjectMap.insert(std::pair<QString, QObject *>(name, obj));
}
在run()调用之后,类进入无限循环,使用m_scriptEngine来评估输入的每个命令行。
在我的(简化)主要内容中:
simuCLI cli;
simuCore core;
cli.addObject(&core, "core");
simuUI ui;
connect(&ui, SIGNAL(start()), &core, SLOT(start()));
但是当我从我的GUI和我的脚本调用start()时,结果是不同的
我的应用程序架构如下:
核心 - &gt; StateMachine - &gt;机器 - &gt;通信
从UI开始工作很棒。
从命令行开始执行代码,但不启动QStateMachine并发出信号,但从不接收它们。
Communication
通过发出Machine
中收到的信号向Machine
发送命令。如果我从我的UI调用core :: start(),它就可以工作
如果我使用命令行调用core :: start(),则信号会被激活但从未接收过。
void WL::WL()
{
std::cout << "wl cst" << std::endl;
mLectMotStateMachine.setInitialState(sNoCard);
mLectMotStateMachine.start();
}
void WL::enterNoCard()
{
std::cout << "no card" << std::endl;
}
输出:
来自UI的start():
wl cst
no card
从命令行start():
wl cst
正如您所看到的,状态机永远不会进入第一个状态,就像它从未启动一样。
所以我的问题是:
1 - 如果我从命令行调用它,那么线程正在执行start()吗?
2 - 如何调试信号? (best answer I've found)
3 - 有没有办法在执行时't'看到每个信号连接
4 - 我怎么知道我在执行哪个帖子?
5 - 您是否知道我的代码仅在我使用命令行时无效?
答案 0 :(得分:1)
您的问题是,在驻留在其他线程中的对象中直接调用线程不安全的方法是错误的。我假设simuCore
对象是QThread
并在其线程中创建了一堆其他对象。这些对象不能直接从其他线程访问,除非你让它们的方法线程安全(你明显没有)。
答案是:
你可以检查一下。在start()
方法中,添加:
qDebug() << QThread::currentThread();
你会看到它与qApp->thread()
的线程相同,也称为主线程或gui线程。
我不知道调试信号是什么意思。信号槽机制显然有效,那么有什么可以调试的呢?
你为什么需要那个?你是那个正在建立(和破坏)连接的人,所以你当然可以在你创建和断开这些连接的位置添加调试输出。没有魔力。
QThread::currentThread()
。
因为你是:
从对象所在的线程以外的线程调用线程不安全的方法。
当你不应该从QThread
派生。
您应该简单地将脚本引擎对象移动到普通的专用QThread
(无子类),并使用线程安全方法调用来评估命令行。信号插槽连接是线程安全的,以及QMetaObject::invokeMethod
。
例如:
#include <QCoreApplication>
#include <QScriptEngine>
#include <QThread>
class ScriptEngine : public QScriptEngine {
Q_OBJECT
Q_SIGNAL void evaluateSignal(const QString &);
public:
Q_SLOT void evaluate(const QString & str) { QScriptEngine::evaluate(str); }
/// A thread-safe evaluate()
Q_SLOT void safeEvaluate(const QString & str) { emit evaluateSignal(str); }
explicit ScriptEngine(QObject * parent = 0) : QScriptEngine(parent) {
connect(this, &ScriptEngine::evaluateSignal, this, &ScriptEngine::evaluate);
}
};
class Thread : public QThread {
// A thread that's safe to destruct, like it ought to be
using QThread::run; // final
public:
~Thread() { quit(); wait(); }
};
int main(int argc, char ** argv) {
QCoreApplication app(argc, argv);
ScriptEngine engine;
Thread worker;
engine.globalObject().setProperty("qApp", engine.newQObject(qApp));
engine.moveToThread(&worker);
worker.start();
QMetaObject::invokeMethod(&engine, "evaluate", Q_ARG(QString, "print('Hi!')"));
engine.safeEvaluate("print('And hello!')");
engine.safeEvaluate("qApp.quit()");
return app.exec();
}
#include "main.moc"