Qt5多线程:信号仅以单向工作

时间:2017-08-07 18:47:29

标签: c++ multithreading qt

此处:Qt multi-thread with GUI我已经学会了如何创建后台工作者(Engine类)。

在该课程中,我有一个QSerialPort对象,在主线程中运行(参见How to setup QSerialPort on a separate thread?)。

我使用信号/插槽机制发送/接收数据。但它只在单向工作。 Engine对象("工作线程")发出的信号由QSerialPort("主线程")接收。反之亦然:QSerialPort未收到Engine发出的任何信号。

engine.h

#ifndef ENGINE_H
#define ENGINE_H

#include <QObject>
#include <QTimer>

#include "myserial.h"

class Engine : public QObject
{
    Q_OBJECT

public:
    explicit Engine(QObject *parent = 0);

private:
    QTimer m_timer;
    MySerial m_serial;

signals:
    void serialSendMessage(QByteArray data);

private slots:
    void lineReceived(QByteArray line);
    void foo();

public slots:
    void run();
    void open(QString port, quint32 baudrate);
    void close();

};

#endif // ENGINE_H

engine.c

#include "engine.h"
#include <QDebug>

Engine::Engine(QObject *parent) : QObject(parent)
{
    connect(&m_timer, &QTimer::timeout, this, &Engine::foo);
    m_timer.setInterval(200);
}

// THIS IS NEVER EXECUTED!
void Engine::lineReceived(QByteArray line)
{
    qDebug() << line;
}

// THIS IS RECEIVED BY QSERIALPORT
void Engine::foo()
{
    emit serialSendMessage("Hello World!");
}

void Engine::run()
{
    // THIS DOESN'T WORK!
    connect(&m_serial, &MySerial::lineReceived, this, &Engine::lineReceived);

    // THIS WORK!
    connect(this, &Engine::serialSendMessage, &m_serial, &MySerial::sendMessage);
}

void Engine::open(QString port, quint32 baudrate)
{
    m_serial.open(port, baudrate);

    QTimer::singleShot(0, &m_timer, static_cast<void (QTimer::*)(void)>(&QTimer::start));
}

void Engine::close()
{
    m_serial.close();
}

MySerial.h

#ifndef MYSERIAL_H
#define MYSERIAL_H

#include <QObject>
#include <QtSerialPort/QSerialPort>
#include <QtSerialPort/QSerialPortInfo>

class MySerial : public QSerialPort {
    Q_OBJECT

public:
    explicit MySerial(QObject *parent = 0);
    bool open(QString port, quint32 baudrate);
    using QSerialPort::open;
    QByteArray sendMessage(QByteArray data, bool nmea);

signals:
    void lineReceived(QByteArray line);

private slots:
    void onReadyRead();
};

#endif // MYSERIAL_H

MySerial.c

#include "myserial.h"
#include <QDebug>

MySerial::MySerial(QObject *parent) : QSerialPort(parent) {
}

bool MySerial::open(QString port, quint32 baudrate)
{
    disconnect(this, 0, 0, 0);
    connect(this, &FemtoSerial::readyRead, this, &MySerial::onReadyRead);

    setPortName(port);
    if (!open(QIODevice::ReadWrite)) return false;
    setDataBits(QSerialPort::Data8);
    setParity(QSerialPort::NoParity);
    setStopBits(QSerialPort::OneStop);
    setBaudRate(baudrate);
    setFlowControl(QSerialPort::NoFlowControl);
    return true;
}

void MySerial::onReadyRead() {
    static QList<QByteArray> lines;
    static QByteArray buffer;

    buffer += readAll();
    int index = buffer.indexOf("\r");
    while (index != -1) {
        lines.append(buffer.left(index + 1));
        buffer = buffer.mid(index + 1);
        index = buffer.indexOf("\r");
    }

    // THIS SIGNAL IS EMITTED!
    while (!lines.isEmpty()) emit lineReceived(lines.takeFirst());
}

QByteArray MySerial::sendMessage(QByteArray data) {
    write(data);
    return data;
}

修改

尝试添加QEventLoop

void Engine::run()
{
    QEventLoop loop;
    connect(&m_serial, &MySerial::lineReceived, this, &Engine::lineReceived);
    connect(this, &Engine::serialSendMessage, &m_serial, &MySerial::sendMessage);    
    loop.exec();
}

行为相同:发送数据,但从不执行接收槽。

1 个答案:

答案 0 :(得分:1)

bool MySerial::open(QString port, quint32 baudrate)
{
    //<s>disconnect(this, 0, 0, 0);</s> // <--- strikeout
    connect(this, &FemtoSerial::readyRead, this, &MySerial::onReadyRead);
    // ...
}

来自文档:

  

断开连接到对象信号的所有内容

     

disconnect(myObject,0,0,0);

它意味着来自myObject的信号,而不是相反。 该行阻止执行Engine中的插槽,因为它刚刚与源信号断开连接。

端口关闭时,

Engine可能会断开连接,以避免下次打开时出现多个连接。