自定义功能中断 [英] Custom function interrupt

查看:94
本文介绍了自定义功能中断的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

是否可以在Qt(5.x)中实现函数中断。

Is it possible to implement function interrupt in Qt (5.x).

例如,如果我有一个按钮,想要在线程上执行某些操作(正在运行无限循环),当单击此按钮时,我可以这样说:

For example if I have a button and want something to execute on the thread (which is running infinite loop) when this button is clicked, I could say something like this:

in thread...
forever
{
  if(button_is_pressed_flag)
  {
    do something...
  }
}

还有更好的方法吗?

推荐答案

无限循环应该是事件循环,然后它可以自动处理跨线程插槽调用,而无需您担心细节。

The infinite loop should be an event loop, and then it can automatically process cross-thread slot calls without you worrying about the details.

惯用语可以连续运行代码事件循环是持续时间为零的计时器。

The idiom to run code "continuously" on an event loop is the zero-duration timer.

让我们从以下代码开始:

Let's say you start with code that looks like this:

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()花费少于1ms的时间可能没有多大意义。

It is required for doWork() not to take too long - nor too short. If it took ~5ms on modern hardware, it'd be just about a right tradeoff between overhead and latency for a general-purpose application. If you need lower latency reaction in the worker thread, then doWork() must do less work. It probably doesn't make much sense for doWork() to take much less than 1ms.

code> doWork()无事可做,例如如果它完成了应该执行的计算,则应该停止使它保持活动状态的计时器。

And whenever doWork() doesn't have anything to do, e.g. if it's done with the computation it was supposed to perform, it should stop the timer that keeps it alive.

您应该将其转换为如下形式:

You should transform it to look as follows:

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 来表示对<$ c $的插槽调用c> QObject :: event ,它将随后执行调用。

The event loop that runs in QThread::run will continuously invoke doWork via the timer event handler. But whenever a cross-thread slot call needs to be made to an object living in that thread, the event loop will deliver the internal QMetaCallEvent representing the slot call to QObject::event, which will then execute the call.

因此,当您在中设置断点时onButtonClick ,调用堆栈附近将有 QObject :: event

Thus, when you set a breakpoint in onButtonClick, there will be QObject::event nearby on the call stack.

这篇关于自定义功能中断的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆