How to implement a QThread that runs forever{} with a QWaitCondition but still needs to catch another Slot while doing that

前端 未结 3 1283
南方客
南方客 2021-01-12 13:29

I implemented a class that can write data to a serial port via a QQueue and read from it by a slot. I use QAsyncSerial for this which in turn uses boost::asio with a callbac

相关标签:
3条回答
  • 2021-01-12 14:01

    This is kind of a shot in the dark, since I'm pretty new to using Qt and I don't know the "usual" approaches to problems like this, but perhaps a call to QCoreApplication::processEvents within the loop would help.

    0 讨论(0)
  • 2021-01-12 14:06

    Unless it's strictly necessary for some reason, I'd get rid of the QWaitCondition. Instead, when the have enqueueMessage() emit a (Qt) signal after it has appended new data to the QQueue, and have your worker thread receive that signal (along with whatever other signals it needs to receive) in the usual Qt way. Then your problem goes away, with no timeouts or other hackery needed.

    (optional optimization: have the serial port only emit the signal if the QQueue was empty before it added the new data, and have the main thread's corresponding slot read from the QQueue until the QQueue is empty -- that can cut down on the number of signals that need to be sent)

    0 讨论(0)
  • 2021-01-12 14:19

    1) Create slot in your thread, for example onMessageReady(), which will do the job.

    2) Create a signal indicates that new message ready, and emit it each time you creating a new message.

    3) Connect them using QueuedConnection and call your thread's exec function.

    This won't block your thread, as WaitforObject does, and you will handle all incoming signals.

    something like this:

    SerialPortHandler: public QThread
    {
      Q_OBJECT
    ...
    signals:
        void sNewMessageReady();
    slots:
        void onNewMessageReady();
        void serialSlotReceivedData(QByteArray);
    };
    
    SerialPortHandler::SerialPortHandler(SerialPort serialPort, QObject *parent) : QThread(parent), serialPort(serialPort)
    {
        m_enqueueMessageMutex = new QMutex();
        m_messageQueue = new QQueue<BaseMessage*>();
        serial.open(serialPort.deviceName(), 2400);
        connect(&serial, SIGNAL(dataReceived(QByteArray)), this, SLOT(serialSlotReceivedData(QByteArray)));
        connect(this, SIGNAL(sNewMessageReady()), this, SLOT(onNewMessageReady()),Qt::QueuedConnection);
    }
    
    void SerialPortHandler::enqueueMessage(BaseMessage *msg)
    {
        QMutexLocker locker(m_enqueueMessageMutex);
        m_messageQueue->enqueue(msg);
        emit sNewMessageReady();
    }
    
    
    void SerialPortHandler::onNewMessageReady()
    {
        QMutexLocker locker(m_enqueueMessageMutex);
        BaseMessage *msg = m_messageQueue->dequeue();
        serial.write(msg->encodeForWriting());
    }
    

    after all simply call thread's exec() method, you don't need to reimplement run() and to use QWaitCondotion at all.

    0 讨论(0)
提交回复
热议问题