C++ 退出前要执行的等待槽

C++ 退出前要执行的等待槽,c++,multithreading,qt,qthread,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(b

我有一个线程可以读取数据

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();
}
问题在于,当我单击“关闭”时,线程被破坏,导致指针
数据
无效。有时会调用信号
newData
,导致我的函数使用无效指针和segfault。如何确定这不会发生

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

我脑海中的想法:
-断开信号
-等待挂起信号执行

-退出

问题在于,您将指针从一个线程发送到另一个线程,但没有确保指针保持有效

你有多种选择来解决这个问题。使用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
}

问题是,您将指针从一个线程发送到另一个线程,而没有确保指针保持有效

你有多种选择来解决这个问题。使用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
}

您所需要做的就是让线程比用户界面更长寿。这相当容易:

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

您所需要做的就是让线程比用户界面更长寿。这相当容易:

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

谢谢你,我试了第一个,它很管用。如果我不想使用动态分配,但想使用address:uint8\u t buffer[size]。。。。。发出缓冲区(&B)[0]。在这种情况下,我能做什么,因为我不希望删除指针(它不能),如果在堆栈上分配缓冲区(而不是在堆上动态分配),则不能保证在调用插槽时它是有效的,因为不能保证缓冲区仍在另一个线程的作用域中。唯一的解决办法是像第三个例子那样复制一份。谢谢你,我肯定需要第一份谢谢,我试了第一份,它正在工作。如果我不想使用动态分配,但想使用address:uint8\u t buffer[size]。。。。。发出缓冲区(&B)[0]。在这种情况下,我能做什么,因为我不希望删除指针(它不能),如果在堆栈上分配缓冲区(而不是在堆上动态分配),则不能保证在调用插槽时它是有效的,因为不能保证缓冲区仍在另一个线程的作用域中。唯一的解决办法是像第三个例子那样复制一份。谢谢你,我肯定需要第一份