c++ - Qt5多线程: signals work in one-way only

标签 c++ multithreading qt

此处:Qt multi-thread with GUI我学习了如何创建后台工作程序(Engine 类)。

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

我正在使用信号/槽机制来发送/接收数据。但它仅以单向方式工作。 Engine 对象(“工作线程”)发出的信号由 QSerialPort(“主线程”)接收。反之亦然:QSerialPort 发出的任何信号都不会被 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

引擎.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();
}

行为是一样的:发送了数据,但是从不执行接收槽。

最佳答案

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

来自文档:

Disconnect everything connected to an object's signals

disconnect(myObject, 0, 0, 0);

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

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

关于c++ - Qt5多线程: signals work in one-way only,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45553794/

相关文章:

c++ - 手动编写的循环与运算符重载的效率

c++ - QT程序无法启动,因为缺少libgcc_s_dw2-1.dll

c++ - Qt3D 几何着色器可以在 QML 中工作,但不能在 C++ 中工作

c++ - 如何在选定的输出设备上使用 native API 在 Windows 上播放声音(mp3/wav)

c++ - 我们如何阅读下面的语句?

c# - 结束线程构造

java - 用Java监控两台打印机

javascript - QML 在 Javascript 设置的属性上返回 NaN

C++:如何将unicode字符打印到文本文件

android - 从 AsyncTask 调用 UI 线程方法