如何在长时间运行的方法中等待信号?

How to wait for signal in long running method?

本文关键字:等待 信号 方法 长时间 运行      更新时间:2023-10-16

目前,我正在flex&bison的基础上开发一种简单的编程语言。

为此,我首先构建抽象语法树(AST(并继续对其进行评估。在评估期间,应能够收到用户输入。用户输入是在Qt-GUI中完成的。ast-evaluation-过程在由 GUI 创建的线程工作线程对象中运行。 我的问题是:哪一种是最好的方法,"阻止"正在运行的flex&bison评估过程,然后从GUI接收用户输入,然后继续执行该过程? 不幸的是,我不知道如何将评估过程分成两部分以捕获来自GUI的用户输入信号,然后在插槽中继续"拆分过程"。 我当前的解决方案(在我看来很差(在评估过程中使用无限循环,直到线程工人对象中的布尔成员变量 (_hasUserInput( 设置为 true。用户输入后,GUI 发出信号。相应的插槽位于线程工作器对象内部。插槽接收用户输入,例如作为 QString 并设置相应的成员变量。此外,布尔变量设置为 true,因此可以保留评估过程的无限循环,可以处理用户输入并继续评估。

功能原理:
GUI -->启动线程(worker-对象(-->启动长期运行过程

伪代码中的示例:

class ThreadWorker : public QObject {
...
// Slot, that reacts to the signal from the GUI
void userInput(const QString &input) {
_userInput = input;
_hasUserInput = true;
}
// evaluation-procedure
void doEvaluation() {
// evaluation of the AST
...
emit userInputRequired();
while (!hasUserInput){          // Check if user input has been done
qApp -> processEvents();    // to react to events
}
do something with user input;
continue valuation;             // Processing of user input and continuation of the procedure
}
...
};

我试图尽可能好地描述我的问题,并希望它能奏效。如果您需要更详细的信息,请询问。 提前非常感谢您的帮助!

由于您已经将工作线程分解到QObject中,因此您永远不需要调用processEvents()。相反,将 AST 评估分解为根据需要执行的小块。我还使公共接口是线程安全的 - 因此您可以直接从任何线程调用它。

// see https://stackoverflow.com/a/40382821/1329652
bool isSafe(QObject * obj);
template <typename Class, typename... Args> void postCall(Class * obj, void (Class::*method)(Args...), Args&& ...args);
class ASTWorker : public QObject {
Q_OBJECT
QBasicTimer m_evaluateTimer; // a bit lower overhead than QTimer
void timerEvent(QTimerEvent * ev) override {
if (ev->timerId() == m_evaluateTimer.timerId())
evaluateImpl();
}
void evaluateImpl() {
bool evaluationDone = {};
QThread::msleep(10); // emulate evaluating a chunk of AST
if (!evaluationDone && !m_evaluateTimer.isActive())
m_evaluateTimer.start(0, this);
else if (evaluationDone)
m_evaluateTimer.stop();
}
public:
using QObject::QObject;
/// Thread-safe
Q_SLOT void setUserInput(const Data & data) {
if (!isSafe(this))
return postCall(this, &ASTWorker::setUserInput, data);
QThread::msleep(1); // emulate processing user data
}
/// Thread-safe
Q_SLOT void evaluate() {
if (!isSafe(this))
return postCall(this, &ASTWorker::evaluate, data);
evaluateImpl();
}
};