Слоты Qt, вызываемые из QtScript в многопоточном приложении

Я сделал свое приложение доступным для сценариев, создав производный класс 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()));

Но когда я вызываю start () из своего графического интерфейса и из своего скрипта, результаты разные

Моя архитектура приложения выглядит следующим образом:

Ядро -> StateMachine -> Машина -> Связь

Запуск из пользовательского интерфейса отлично работает.

Запустить из командной строки выполнить код, но не запускать QStateMachine, и он испускает сигналы, но никогда их не получает.

Communication отправляет команды Machine, испуская сигналы, полученные в Machine. Он работает, если я вызываю 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;
}

Выход:

start () из пользовательского интерфейса:

wl cst
no card

start () из командной строки:

wl cst

Как видите, конечный автомат никогда не входит в свое первое состояние, как и никогда не запускается.

Итак, мои вопросы:

1 - В каком потоке выполняется start (), если я вызываю его из командной строки?

2 - Как я могу отлаживать сигналы? (лучший ответ, который я нашел)

3 - Есть ли способ увидеть каждое соединение сигналов в момент t при выполнении

4 - Как я могу узнать, в каком потоке я нахожусь в процессе выполнения?

5. У вас есть идеи, почему мой код не работает только тогда, когда я использую командную строку?


person MokaT    schedule 17.07.2014    source источник
comment
Проверьте свои соединения, особенно, если start () соединения должен быть активирован с помощью. Для получения дополнительной помощи укажите код, пожалуйста.   -  person Sebastian Lange    schedule 17.07.2014
comment
Я полностью отредактировал свой пост, чтобы он был более откровенным   -  person MokaT    schedule 17.07.2014


Ответы (1)


Ваша проблема в том, что прямой вызов небезопасных для потоков методов в объектах, которые находятся в других потоках, является ошибкой. Я предполагаю, что объект simuCore является QThread и создает кучу других объектов в своем потоке. К этим объектам нельзя получить доступ из других потоков напрямую, если вы не сделаете их методы потокобезопасными (что явно не так).

Ответы таковы:

  1. Вы можете это проверить. В методе start() добавьте:

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

    Вы увидите, что это тот же поток, что и qApp->thread(), также известный как основной поток или поток графического интерфейса.

  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"
person Kuba hasn't forgotten Monica    schedule 18.07.2014
comment
Вау, спасибо. Это реальная реализация QThread. Я нашел это кто может быть полезен. - person MokaT; 18.07.2014
comment
И отличный пример от Qt Dev Andre на ссылку на класс QThread. - person MokaT; 18.07.2014
comment
Примечание. Вызов qApp.quit() - это гонка с app.exec(), есть вероятность, что он будет выполнен в рабочем потоке до входа app.exec(), и тогда он не будет работать. TODO позже :) - person Kuba hasn't forgotten Monica; 18.07.2014