Multithreading Can';t退出Qt中的exec循环

Multithreading Can';t退出Qt中的exec循环,multithreading,qt,Multithreading,Qt,我创建了一个程序,从串行输入中提取输入信号。我可以通过UART成功接收设备发送的数据。我想在达到某些条件后终止线程(例如接收超过5个字节等),我认为问题在于如何在Qt中正确终止线程,但我找不到方法。调用子函数中的exec()后,程序似乎陷入死锁。有人能帮忙解决这个问题吗?多谢各位 这是我的头文件: #ifndef SERIALTHREAD #define SERIALTHREAD #include <QtSerialPort/QSerialPort> #include <QD

我创建了一个程序,从串行输入中提取输入信号。我可以通过UART成功接收设备发送的数据。我想在达到某些条件后终止线程(例如接收超过5个字节等),我认为问题在于如何在Qt中正确终止线程,但我找不到方法。调用子函数中的exec()后,程序似乎陷入死锁。有人能帮忙解决这个问题吗?多谢各位

这是我的头文件:

#ifndef SERIALTHREAD
#define SERIALTHREAD

#include <QtSerialPort/QSerialPort>
#include <QDebug>

#include <QString>
#include <QThread>
#include <QtCore>

#include <iostream>
#include <fstream>


class SerialControlThread : public QThread
{
   Q_OBJECT
  public:

  explicit SerialControlThread(QString ComPort,QObject *parent = 0);
  ~SerialControlThread(); // Destructor

    bool openSerialPort();
    void closeSerialPort();
    void run();
    bool TelltoExit();
    void StarttoRun();


   private:

     int DataCount;

     QString ComPortNumber;
     QSerialPort *serial;

     int* VoltageStorage; // Total 3 channels, each channel takes 10 data

     unsigned int Channel_A[10]; // Channel_A is for Phase Tx s

     int DataCountIndexA; // This is how many data has been sent to the buffer;

     int SentDataCount;
     unsigned char StoreDataBuffer[2];

     unsigned char TotalDataCounter;

     std::ofstream write;

  signals:
      void BufferisFull(int*);
      void TimeToQuit();



public slots:


private slots:
    void readData();
    void handleError(QSerialPort::SerialPortError error);

};

#endif // SERIALTHREAD

显然,程序陷入了一个循环。我试过一些解决办法,但都不管用

StartToRun
在错误的线程中调用
QThread::exec
:您在主线程中调用它,但它应该在线程本身中调用-从
run()
中调用

唉,
SerialControlThread
不一定是线程。将其设置为线程将强制在专用线程中使用-这应该是留给用户的选择。也许这个线程可以在其他串行控制器之间共享,或者在主线程中也可以。因此,它应该是一个处理串行数据的对象,它有一个线程安全接口,以便您可以根据需要将其移动到另一个线程,但在主线程中仍然可以正常工作,因此必须在不阻塞的情况下异步处理数据

考虑到是否需要如此严格地控制工作线程的运行状态:空闲线程不消耗任何资源——它的事件循环在等待新事件时被阻塞,如果内存不足,它的堆栈最终会被调出。如果打算为每个操作“唤醒”线程,则无需对此进行明确说明:线程中的事件循环的行为方式是默认的,并且是按设计的:当出现新事件(如传入数据)时,它将唤醒,否则它将休眠。我们不应该停止线程

下面的示例显示了一个非常简单的实现。总的来说,除了与问题中的代码长度相比表现出简洁性之外,它并不是很有用——尽管相同的功能有限。您可能希望处理一个更复杂的通信协议。您可能希望考虑使用使读者代码更具表现力,以及

//https://github.com/KubaO/stackoverflown/tree/master/questions/serial-galore-42241570
#包括
#包括
//看https://stackoverflow.com/q/40382820/1329652
模板无效安全(QObject*obj,乐趣和乐趣){
Q|u断言(obj->thread()| | qApp&&qApp->thread()==QThread::currentThread());
如果(Q|u可能(obj->thread()==QThread::currentThread()| |!obj->thread())
返回乐趣();
结构事件:公共QEvent{
使用F=typename std::decay::type;
F乐趣;
事件(F&&fun):QEvent(QEvent::None),fun(std::move(fun)){}
事件(const F&fun):QEvent(QEvent::None),fun(fun){
~Event(){fun();}
};
QCoreApplication::postEvent(
obj->thread()?obj:qApp,新事件(std::forward(fun));
}
类SerialController:公共QObject{
Q_对象
QSerialPort m_端口{this};
QByteArray m_rxData;
void onError(QSerialPort::SerialPortError错误){
Q_未使用(错误);
}
void onData(常数QByteArray和数据){
m_rxData.append(数据);

qDebug()对这段代码的简要扫描发现:`delete RunThread;return a.exec();`不确定其他事情,但这一点显然是错误的。主线程在
a.exec()
中旋转,当主线程进入其事件循环时,另一个线程应该处于活动状态?
#include "serialcontrol.h"
#include <iostream>

SerialControlThread::SerialControlThread(QString ComPort,QObject *parent) :
    QThread(parent),ComPortNumber(ComPort)
{

    DataCountIndexA=0;

    DataCount=0;

    serial = new QSerialPort(this);

    connect(this,SIGNAL(TimeToQuit()),this,SLOT(quit()));\
    connect(serial, SIGNAL(readyRead()), this, SLOT(readData()));
    connect(serial, SIGNAL(error(QSerialPort::SerialPortError)), this,
            SLOT(handleError(QSerialPort::SerialPortError)));

    for (int i=0;i<10;i++)
      Channel_A[i]=0;


}

SerialControlThread::~SerialControlThread()
{

    this->closeSerialPort();
    delete serial;
}

bool SerialControlThread::openSerialPort()
{

  //  std::cout << "Hey I am in serial function" << std::endl;

    serial->setPortName(ComPortNumber) ;
    serial->setBaudRate(QSerialPort::Baud9600); //This can be set through menu in the future
    serial->setDataBits(QSerialPort::Data8); // A packets contains 8 bits ( 3 for signature bits)
    serial->setParity(QSerialPort::NoParity);
    serial->setStopBits(QSerialPort::OneStop);
    serial->setFlowControl(QSerialPort::NoFlowControl);

    if (!(serial->open(QIODevice::ReadWrite))) {

    return false;  // return false when the device can't be opened
     }else
    {
     return true;} // return true when the device is avalaible

}

void SerialControlThread::closeSerialPort()
{
    if (serial->isOpen())
        serial->close();
}

void SerialControlThread::handleError(QSerialPort::SerialPortError error)
{


}

void SerialControlThread::readData()
{
    QByteArray data=serial->read(100);
    const char *TempChar=data.data();

    std::cout << TempChar << std::endl;

    DataCount++;

   if(DataCount>=4)
    {
       std::cout << "I am bigger than 4" << std::endl;
       this->quit();
     }
   }

}

void SerialControlThread::run()
{





}
bool SerialControlThread::TelltoExit()
{

}

void SerialControlThread::StarttoRun()
{

        // Sending the msp430 S to activate the following sequence
            const char *temp="S";
           serial->write(temp);
           serial->waitForBytesWritten(30000);
           this->exec();

}
#include <QCoreApplication>
#include <QtSerialPort/QSerialPortInfo>
#include <QList>
#include <iostream>
#include <QString>
#include <QDebug>
#include <QSerialPort>

#include "serialcontrol.h"

using namespace std;


int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);



   int AvailablePorts=QSerialPortInfo::availablePorts().count();
   QList<QSerialPortInfo> SerialObject=QSerialPortInfo::availablePorts();


   cout <<  "There are total: " << SerialObject.count() <<  " available ports " << endl << endl;


   QString description;



   for (int i=0;i<AvailablePorts;i++)
   {
       cout << "The " << i+1 << " com port is :";
       qDebug() <<  SerialObject[i].portName();
       qDebug() << "Description : " <<  SerialObject[i].description();
       qDebug() << "Manufacturer: " <<  SerialObject[i].manufacturer();

       cout << endl;
   }



   SerialControlThread *RunThread=new SerialControlThread(SerialObject[0].portName(),&a);


   cout << RunThread->openSerialPort() << endl;
   RunThread->StarttoRun();




   cout << "I am out of here" << endl;


    delete RunThread;






    return a.exec();
}
There are total: 1 available ports

The 1 com port is :"COM8"
Description :  "MSP430 Application UART"
Manufacturer:  "Texas Instruments"

1
0
1
2
3
I am bigger than 4
4
I am bigger than 4
5
I am bigger than 4
6
I am bigger than 4
7
I am bigger than 4
8
I am bigger than 4
9
I am bigger than 4
// https://github.com/KubaO/stackoverflown/tree/master/questions/serial-galore-42241570
#include <QtWidgets>
#include <QtSerialPort>

// See https://stackoverflow.com/q/40382820/1329652
template <typename Fun> void safe(QObject * obj, Fun && fun) {
   Q_ASSERT(obj->thread() || qApp && qApp->thread() == QThread::currentThread());
   if (Q_LIKELY(obj->thread() == QThread::currentThread() || !obj->thread()))
      return fun();
   struct Event : public QEvent {
      using F = typename std::decay<Fun>::type;
      F fun;
      Event(F && fun) : QEvent(QEvent::None), fun(std::move(fun)) {}
      Event(const F & fun) : QEvent(QEvent::None), fun(fun) {}
      ~Event() { fun(); }
   };
   QCoreApplication::postEvent(
            obj->thread() ? obj : qApp, new Event(std::forward<Fun>(fun)));
}

class SerialController : public QObject {
   Q_OBJECT
   QSerialPort m_port{this};
   QByteArray m_rxData;

   void onError(QSerialPort::SerialPortError error) {
      Q_UNUSED(error);
   }
   void onData(const QByteArray & data) {
      m_rxData.append(data);
      qDebug() << "Got" << m_rxData.toHex() << "(" << m_rxData.size() << ") - done.";
      emit hasReply(m_rxData);
   }
   void onData() {
      if (m_port.bytesAvailable() >= 4)
         onData(m_port.readAll());
   }
public:
   explicit SerialController(const QString & port, QObject * parent = nullptr) :
      QObject{parent}
   {
      m_port.setPortName(port);
      connect(&m_port, static_cast<void(QSerialPort::*)(QSerialPort::SerialPortError)>(&QSerialPort::error),
              this, &SerialController::onError);
   }
   ~SerialController() { qDebug() << __FUNCTION__; }
   bool open() {
      m_port.setBaudRate(QSerialPort::Baud9600);
      m_port.setDataBits(QSerialPort::Data8);
      m_port.setParity(QSerialPort::NoParity);
      m_port.setStopBits(QSerialPort::OneStop);
      m_port.setFlowControl(QSerialPort::NoFlowControl);
      return m_port.open(QIODevice::ReadWrite);
   }
   /// This method is thread-safe.
   void start() {
      safe(this, [=]{
         m_port.write("S");
         qDebug() << "Sent data";
      });
   }
   Q_SIGNAL void hasReply(const QByteArray &);
   void injectData(const QByteArray & data) {
      onData(data);
   }
};

QDebug operator<<(QDebug dbg, const QSerialPortInfo & info) {
   dbg << info.portName();
   if (!info.description().isEmpty())
       dbg << " Description: " <<  info.description();
   if (!info.manufacturer().isEmpty())
       dbg << " Manufacturer: " <<  info.manufacturer();
   return dbg;
}

// A thread that starts on construction, and is always safe to destruct.
class RunningThread : public QThread {
   Q_OBJECT
   using QThread::run; // final
public:
   RunningThread(QObject * parent = nullptr) : QThread(parent) { start(); }
   ~RunningThread() { qDebug() << __FUNCTION__; quit(); wait(); }
};

int main(int argc, char *argv[])
{
   QCoreApplication app(argc, argv);
   auto const ports = QSerialPortInfo::availablePorts();
   if (ports.isEmpty())
      qFatal("No serial ports");

   int n{};
   qDebug() << "Available ports:";
   for (auto & port : ports)
      qDebug() << "port[" << n++ << "]: " << port;

   SerialController ctl{ports.at(5).portName()};
   if (!ctl.open())
      qFatal("Open Failed");

   // Optional: the controller will work fine in the main thread.
   if (true) ctl.moveToThread(new RunningThread{&ctl}); // Owns its thread

   // Let's pretend we got a reply;
   QTimer::singleShot(1000, &ctl, [&ctl]{
      ctl.injectData("ABCD");
   });
   QObject::connect(&ctl, &SerialController::hasReply, ctl.thread(), &QThread::quit);
   QObject::connect(&ctl, &SerialController::hasReply, [&]{
      qDebug() << "The controller is done, quitting.";
      app.quit();
   });
   ctl.start();
   return app.exec();
}
#include "main.moc"