从线程应用程序中的QtScript调用的Qt插槽

Qt slots called from QtScript in a threaded application

本文关键字:调用 Qt 插槽 QtScript 应用程序 线程      更新时间:2023-10-16

我通过创建一个派生的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((时,结果是不同的

我的应用程序架构如下所示:

核心 -> 状态机 -> 机器 -> 通信

从 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 开始((:

wl cst
no card

从命令行开始((:

wl cst

如您所见,状态机永远不会进入它的第一个状态,就像它永远不会启动一样。

所以我的问题是:

1 - 如果我从命令行调用它,线程正在执行 start(( ?

2 - 如何调试信号?(我找到的最佳答案(

3 - 有没有办法在执行时一次查看每个信号连接 't'

4 - 我怎么知道我在哪个线程中执行?

5 - 您是否知道为什么我的代码仅在使用命令行时才不起作用?

您的问题是,在驻留在其他线程中的对象中直接调用线程不安全的方法是一个错误。我假设simuCore对象是一个QThread,并在其线程中创建一堆其他对象。这些对象不能直接从其他线程访问,除非您使它们的方法线程安全(您显然不会(。

答案是:

  1. 你可以检查一下。在start()方法中,添加:

    qDebug() << QThread::currentThread();
    

    你会看到它与qApp->thread()是同一个线程,也称为主线程或 gui 线程。

  2. 我不知道你说的调试信号是什么意思。信号槽机制显然有效,那么有什么要调试的呢?

  3. 你为什么需要它?您是建立(和断开(连接的人,因此您当然可以在建立和断开这些连接的位置添加调试输出。没有魔法。

  4. QThread::currentThread() .

  5. 因为你是:

    • 从对象所在的线程以外的线程调用线程不安全的方法。

    • 在你不应该的时候从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"