我实现了一个类,它可以通过QQueue将数据写入串口并通过插槽读取.我使用QAsyncSerial来反过来使用boost :: asio和回调.
该类被移动到一个线程,并且当QThread发出“started()”时执行其start()方法
该类被移动到一个线程,并且当QThread发出“started()”时执行其start()方法
问题是我使用forever {}和QWaitCondition在start()方法中将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运行中调用了回调.因为它有自己的线程,所以ThreadPortHandler运行的线程被永久循环阻塞并不重要.
新代码:(因为QAsyncSerial类似于CallbackAsyncSerial的包装,只有一些微不足道的事情发生了变化)
SerialPortHandler::SerialPortHandler(SerialPort serialPort,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,_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(); } }
解决方法
1)在你的线程中创建插槽,例如onMessageReady(),它将完成这项工作.
2)创建一个信号表示新消息准备就绪,并在每次创建新消息时发出.
3)使用QueuedConnection连接它们并调用线程的exec函数.
这不会像WaitforObject那样阻塞你的线程,你将处理所有传入的信号.
像这样的东西:
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(),SLOT(serialSlotReceivedData(QByteArray))); connect(this,SIGNAL(sNewMessageReady()),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()); }