Как реализовать QThread, который будет работать вечно {} с QWaitCondition, но все еще должен поймать другой слот при этом

Я реализовал класс, который может записывать данные в последовательный порт через QQueue и читать из него через слот. Я использую для этого QAsyncSerial, который, в свою очередь, использует boost :: asio с обратным вызовом. Класс перемещается в поток, и его метод start () выполняется, когда QThread испускает "start ()"

. Проблема в том, что я удаляю QQueue из очереди в методе start (), используя forever {} и QWaitCondition. Пока он работает (который, очевидно, работает вечно), слот, подключенный к сигналу dataReceived QAsyncSerial, не может быть вызван, поэтому я никогда ничего не читаю из последовательного порта.

Каков обычный подход к этой проблеме?

SerialPortHandler::SerialPortHandler(SerialPort serialPort, QObject *parent) : QObject(parent), serialPort(serialPort)
{
    m_enqueueMessageMutex = new QMutex();
    m_messageQueue = new QQueue<BaseMessage*>();
    m_waitCondition = new QWaitCondition();
    serial.open(serialPort.deviceName(), 2400);
    connect(&serial, SIGNAL(dataReceived(QByteArray)), this, SLOT(serialSlotReceivedData(QByteArray)));
}

void SerialPortHandler::serialSlotReceivedData(QByteArray line)
{
    qDebug() << QString(line).toAscii();
}

void SerialPortHandler::sendTestPing()
{
    PingMessage *msg = new PingMessage();
    enqueueMessage(msg);
}

void SerialPortHandler::enqueueMessage(BaseMessage *msg)
{
    QMutexLocker locker(m_enqueueMessageMutex);
    m_messageQueue->enqueue(msg);
    m_waitCondition->wakeAll();
}

void SerialPortHandler::start()
{
    if (!serial.isOpen())
        return;

    forever {
        m_enqueueMessageMutex->lock();
        if (m_messageQueue->isEmpty())
            m_waitCondition->wait(m_enqueueMessageMutex);
        BaseMessage *msg = m_messageQueue->dequeue();
        serial.write(msg->encodeForWriting());
        m_enqueueMessageMutex->unlock();
    }
}

изменен обратный вызов QAsyncSerial, используемый boost :: asio:

void QAsyncSerial::readCallback(const char *data, size_t size)
{
    emit dataReceived(QByteArray::fromRawData(data, (int) size));
}

Изменить:

Я решил эту проблему другим подходом. Я отказался от QAsyncSerial и вместо этого использовал CallbackAsyncSerial, который также напрямую распространяется QAsyncSerial. Теперь обратный вызов, используемый boost :: asio, - это «слот» serialSlotReceivedData. Это «решает» проблему, поскольку обратный вызов вызывается в потоке, в котором выполняется boost :: asio. Поскольку у него есть собственный поток, не имеет значения, что поток, в котором выполняется SerialPortHandler, заблокирован циклом forever.

Новый код : (поскольку QAsyncSerial является чем-то вроде оболочки для CallbackAsyncSerial, изменились только некоторые тривиальные вещи)

SerialPortHandler::SerialPortHandler(SerialPort serialPort, QObject *parent) : QObject(parent), serialPort(serialPort)
{
    m_enqueueMessageMutex = new QMutex();
    m_messageQueue = new QQueue<BaseMessage*>();
    m_waitCondition = new QWaitCondition();
    /* serial is now CallbackAsyncSerial and not QAsyncSerial */
    serial.open(QString(serialPort.deviceName()).toStdString(), 2400);
    serial.setCallback(bind(&SerialPortHandler::serialSlotReceivedData, this, _1, _2));

    m_messageProcessingState = MessageProcessingState::Inactive;
}

void SerialPortHandler::start()
{
    if (!serial.isOpen())
        return;

    forever {
        m_enqueueMessageMutex->lock();

        if (m_messageQueue->isEmpty())
            m_waitCondition->wait(m_enqueueMessageMutex);

        BaseMessage *msg = m_messageQueue->dequeue();
        QByteArray encodedMessage = msg->encodeForWriting();
        serial.write(encodedMessage.constData(), encodedMessage.length());

        m_enqueueMessageMutex->unlock();
    }
}
7
задан Strayer 24 May 2011 в 10:01
поделиться