我实现了一个类,它可以通过 QQueue 将数据写入串行端口并通过插槽从中读取。我为此使用 QAsyncSerial ,它反过来使用 boost::asio 和回调。该类被移动到一个线程,并且当 QThread 发出“started()”时执行它的 start() 方法
问题是我在 start() 方法中使用 forever {} 和 QWaitCondition 使 QQueue 出队。虽然它正在运行(显然永远运行),但无法调用连接到 QAsyncSerial 的 dataReceived 信号的插槽,因此我从未从串行端口读取任何内容。
解决这个问题的常用方法是什么?
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();
}
}
boost::asio 使用的更改后的 QAsyncSerial 回调:
void QAsyncSerial::readCallback(const char *data, size_t size)
{
emit dataReceived(QByteArray::fromRawData(data, (int) size));
}
编辑:
我用另一种方法解决了这个问题。我放弃了 QAsyncSerial,而是使用了 CallbackAsyncSerial,它也由 QAsyncSerial 直接分发。现在 boost::asio 使用的回调是 serialSlotReceivedData "slot"。这“解决”了问题,因为在线程 boost::asio 运行时调用了回调。由于它有自己的线程,因此 SerialPortHandler 运行的线程被永远循环阻塞并不重要。
新代码:(因为 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();
}
}