是否可以在Qt(5.x)中实现函数中断。
例如,如果我有一个按钮并且想要在线程上执行某些操作(运行无限循环),单击此按钮时,我可以这样说:
in thread...
forever
{
if(button_is_pressed_flag)
{
do something...
}
}
有更好的方法吗?
答案 0 :(得分:3)
无限循环应该是一个事件循环,然后它可以自动处理跨线程插槽调用,而不必担心细节。
运行代码的习语"不断地"在事件循环中是零持续时间计时器。
我们假设您从代码如下开始:
class MyThread : public QThread {
bool button_is_clicked_flag = false;
void run() override {
forever{
if (button_is_clicked_flag) {
onButtonClick();
button_is_clicked_flag = false;
}
doWork();
}
}
void onButtonClick();
void doWork();
public:
using QThread::QThread;
void setButtonClickedFlag();
}
int main(int argc, char **argv) {
...
MyThread t;
t.start();
...
}
doWork()
要求不要花太长时间 - 也不要太短。如果在现代硬件上花费大约5毫秒,那么它只是在通用应用程序的开销和延迟之间进行正确的权衡。如果在工作线程中需要较低的延迟响应,那么doWork()
必须做的工作量减少。 doWork()
花费不到1毫秒的时间可能没什么意义。
只要doWork()
没有任何事情可做,例如如果它完成了它应该执行的计算,它应该停止使它保持活动的计时器。
您应该将其转换为如下所示:
class MyWorker : public QObject {
Q_OBJECT
QBasicTimer m_timer;
void doWork();
void timerEvent(QTimerEvent *event) {
if (event->timerId() == m_timer.timerId())
doWork();
}
public:
explicit MyWorker(QObject *parent = nullptr) : QObject(parent) {
m_timer.start(0, this);
}
Q_SLOT void onButtonClick() {
// Ensure we're invoked correctly
Q_ASSERT(QThread::currentThread() == thread());
...
}
}
class Window : public QWidget {
Ui::Window ui;
public:
Q_SIGNAL void buttonClicked();
explicit Window(QWidget *parent = nullptr) : QWidget(parent) {
ui.setupUi(this);
connect(ui.button, &QPushButton::clicked, this, &Window::buttonClicked);
}
};
class SafeThread : public QThread {
Q_OBJECT
using QThread::run; // final method
public:
~SafeThread() { quit(); wait(); } // we're safe to destroy - always
};
int main(int argc, char **argv) {
...
MyWorker worker;
SafeThread thread;
Window window;
// onButtonClick will be executed in worker->thread()
connect(&window, &Window::buttonClicked, &worker, &MyWorker::onButtonClick);
worker.moveToThread(&thread);
thread.start();
window.show();
return app.exec();
}
在QThread::run
中运行的事件循环将通过计时器事件处理程序不断调用doWork
。但是,只要需要对生成在该线程中的对象进行跨线程槽调用,事件循环就会将表示槽调用的内部QMetaCallEvent
传递给QObject::event
,然后执行该调用。
因此,当您在onButtonClick
中设置断点时,调用堆栈附近会有QObject::event
。
答案 1 :(得分:1)
你可以启动一个线程,然后立即等待std :: condition_variable,然后当单击该按钮时(在主线程上调用该事件),通知条件变量并且线程将唤醒。
然而,这有点奇怪。你想做什么?单击按钮时调用异步任务?在这种情况下,也许最好只使用std :: packaged_task或std :: async从按钮单击事件启动一个。