Я реализовал класс, который может записывать данные в последовательный порт через 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));
}
Edit:
Я решил эту проблему другим подходом. Я отказался от 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();
}
}