退出前等待插槽

时间:2017-01-16 13:55:07

标签: c++ multithreading qt qthread

我有一个读取数据的线程

class MyThread: QThread
{
  ...
}

void MyThread::run ()
{
  uint8_t* buffer; // in my real code, it's a ring, so there is not read during write
  // ...

  while (true)
  {
    if (isInterruptionRequested())
      return;
    USB_READ(buffer);
    emit newData(buffer);
  }
}

在我的UI类中,我有:

connect(this, &UIClass::newData, m_thread, &MyThread::newData);

// ...

void newData(uint8_t* data)
{
  // Process data
}

void UIClass::closeEvent(QCloseEvent *event)
{
   disconnect(this, &UIClass::newData, m_thread, &MyThread::newData);
   m_thread->requestInterruption();
   m_thread->wait();
}

问题是,当我点击“关闭”时,线程被销毁导致指针data无效。有时调用信号newData会导致我的函数使用无效指针和段错误。如何确定不会发生?

现在,我使用一个带有任意延迟的std :: this_thread :: sleep_for(),它可以工作,但我觉得这不是很漂亮

我心中想到:
   - 断开信号
   - 等待执行挂起信号    - 退出

2 个答案:

答案 0 :(得分:2)

问题是你从一个线程发送指针到另一个线程而不确保指针保持有效。

您有多种选择来解决这个问题。要么使用QSharedPointer(或来自stl的类似实用程序)来保存数据,这样做会确保指针保持有效(或者如果你也使用QWeakPointer,则提供一种方法来检测指针何时变为无效)。或者您可以使用QByteArray传递数据,但这将复制。

示例1

void MyThread::run ()
{
  QSharedPointer<uint8_t> buffer (new uint8_t[N]()); // Do not delete[], QSharedPointer will handle it
  ...

  emit newData(buffer);

}
void newData(QSharedPointer<uint8_t> data)
{
  // data is always valid
  // Process data
}

示例2

void MyThread::run ()
{
  QSharedPointer<uint8_t> buffer (new uint8_t[N]());
  ...

  emit newData(buffer);

}
void newData(QWeakPointer<uint8_t> data)
{
  // data might not be valid but we can check
  QSharedPointer<uint8_t> buffer (data);
  if (!buffer)
      return;
  // Process data
}

示例3

void MyThread::run ()
{
  uint8_t[N] buffer;
  ...

  emit newData(QByteArray(buffer, size));

}
void newData(QByteArray data)
{
  // data is valid
  // Process data
}

答案 1 :(得分:0)

您需要做的就是让线程比用户界面更长久。这很容易:

class MyThread : public QThread
{
  Q_OBJECT
  RingBuffer buffer;
public:
  void run() override;
  ~MyThread() {
     requestInterruption();
     quit();
     wait();
  }
  Q_SIGNAL newData(RingBuffer *);
};

int main(int argc, char **argv) {
  QApplication app{argc, argv};
  MyThread thread;
  thread.start();
  UIClass ui;
  connect(&thread, &MyThread::newData, &ui, &UIClass::newData);
  return app.exec();
}