c – 如何使用QWaitCondition实现一个永远运行的QThread但仍然需要在执行此操作时捕获另一个Slot

前端之家收集整理的这篇文章主要介绍了c – 如何使用QWaitCondition实现一个永远运行的QThread但仍然需要在执行此操作时捕获另一个Slot前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我实现了一个类,它可以通过QQueue将数据写入串口并通过插槽读取.我使用QAsyncSerial来反过来使用boost :: asio和回调.
该类被移动到一个线程,并且当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());
}

毕竟只是调用线程的exec()方法,你不需要重新实现run()并使用QWaitCondotion.

原文链接:https://www.f2er.com/c/119169.html

猜你在找的C&C++相关文章