简体   繁体   English

退出前要等待的插槽

[英]Waiting slots to be executed before quitting

I've a thread that read datas 我有一个读取数据的线程

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);
  }
}

In my UI Class I have: 在我的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();
}

The problem with that if, when I click on "close", the thread is destroyed that cause the pointer data to be invalid. 问题是,当我单击“关闭”时,线程被破坏导致指针data无效。 The signal newData is sometimes called that cause my function to work with invalid pointer and segfault. 有时会调用信号newData ,导致我的函数使用无效的指针和segfault。 How to be sure that is not gonna happend ? 如何确保不会发生?

For now, I use a std::this_thread::sleep_for() with an arbitrary delay, it works, but I not find this very beautiful 现在,我使用std :: this_thread :: sleep_for()任意延迟,它可以工作,但是我觉得这不是很漂亮

That I have in my mind : 我的想法是:
- disconnect the signal -断开信号
- wait for the pendings signals to be executed -等待待处理信号被执行
- exit - 出口

The problem is that you send a pointer from one thread to another without ensuring the pointer stays valid. 问题是您从一个线程向另一个线程发送了一个指针,而没有确保该指针保持有效。

You have multiple choices to solve this. 您有多种选择来解决此问题。 Either use QSharedPointer (or similar utilities from the stl) to hold your data, doing so will ensure your pointer will remain valid (or provide you a way to detect when the pointer becomes invalid if you also use QWeakPointer). 使用QSharedPointer(或stl中的类似实用程序)来保存数据,这样做可以确保您的指针保持有效(或者如果您还使用QWeakPointer,则可以为您提供一种检测指针何时变为无效的方法)。 Or you could make use of QByteArray to pass the data, but this will make a copy. 或者,您可以使用QByteArray传递数据,但这将创建一个副本。

Example 1 例子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
}

Example 2 例子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
}

Example 3 例子3

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

  emit newData(QByteArray(buffer, size));

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

All you need to do is for the thread to outlive the user interface. 您所需要做的就是让线程在用户界面上保持生存。 That's rather easy: 那很简单:

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();
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM