LINUX.ORG.RU

Qt5, не проходит сигнал/слот

 


1

1

Народ, столкнулся с проблемой не проходит сигнал/слот в след конструкции:
classes.hpp

#ifndef CLASSES_HPP
#define CLASSES_HPP
#include <QObject>
#include <QTextStream>
#include <QThread>

#include <iostream>


/// controller
class Controller: public QObject {
    Q_OBJECT
public:
    Controller(QObject *parent = Q_NULLPTR ): QObject(parent),m_enable(false){
        std::cout << "Controller" << std::endl;
    }
    ~Controller(){
        std::cout << "~Controller" << std::endl;
    }

public slots:
    void put( const QString & msg ){
        QString str( msg );
        std::cout << str.toStdString() << std::endl;
    }
};
/// Writer
class Writer : public QObject {
    Q_OBJECT

signals:
    void send( const QString & msg );

public:
    Writer( QObject * parent = 0 ): QObject(parent){
        std::cout << "Writer" << std::endl;

    }
    ~Writer(){
        std::cout << "~Writer" << std::endl;
    }

public slots:
    void write(){
        QThread *   pthread = QThread::currentThread();
        for ( int i=0; i<1000; i++ ){
            QString str;
            QTextStream( &str ) << "write: " << i;
            emit send( str );
        }
        pthread->quit();
    }
};
#endif // CLASSES_HPP

main.cpp
#include <QCoreApplication>
#include "classes.hpp"

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    Controller ctrl( &a );

    ctrl.put( QString("step1") );
    ctrl.put( QString("step2") );

    QThread * pThread = new QThread( &a );
    Writer * pWriter = new Writer( 0 );
    pWriter->moveToThread( pThread );

    QObject::connect(pThread, &QThread::finished,   pWriter,    &QObject::deleteLater );
    QObject::connect(pThread, &QThread::finished,   pThread,    &QObject::deleteLater );
    QObject::connect(pWriter, &Writer::send,        &ctrl,      &Controller::put, Qt::BlockingQueuedConnection/*Qt::QueuedConnection*/ );
    QObject::connect(pThread, &QThread::started,    pWriter,    &Writer::write );

    pThread->start();

    std::cout << "started" << std::endl;
    pThread->wait();
    std::cout << "waited" << std::endl;

    delete pThread;

    return 0;
}

Если указан Qt::BlockingQueuedConnection, то программа лочится на первом emit send во врайтере, если просто Qt::QueuedConnection, то
цикл пролетает и слот контроллера не вызывается. Где собака порылась?
Спасибо
★★

Может стоит начать с того, что выкинуть iostream и использовать qDebug?

Ну и вызывать send по таймеру, а не в цикле. Вы же блочите поток. Но это так, мысли в слух.

RazrFalcon ★★★★★ ()
Ответ на: комментарий от asaw

если оставить итерацию одну - все тоже самое. QThread в своем методе run вызывает exec как бы ...

PETER ★★ ()
Ответ на: комментарий от RazrFalcon

не имеет большого значения, да и таймер ни к чему. Задача простая - запустить поток в рамках Qt и писать из него в controller

PETER ★★ ()
Ответ на: комментарий от PETER

А вот когда ты делаешь QObject::connect(pThread, &QThread::started, pWriter, &Writer::write ); живущими в одном потоке после pWriter->moveToThread( pThread ); с Qt::BlockingQueuedConnection ты закономерно получаешь дедлок.

asaw ★★★★★ ()
Ответ на: комментарий от PETER

Да, а контроллер то у тебя живет в основном потоке? И кто же там вызывает обработчик событий, пока выполняется main?

asaw ★★★★★ ()
Ответ на: комментарий от asaw

значит контроллер нужно засунуть в отдельный поток :)

PETER ★★ ()
Ответ на: комментарий от PETER

Если ты изображаешь модель акторов, то да.

asaw ★★★★★ ()
Ответ на: комментарий от PETER

controller.h

#ifndef CONTROLLER_H
#define CONTROLLER_H

#include <QObject>
#include <QTimer>
#include <QDebug>

class Controller: public QObject
{
    Q_OBJECT

public:
    Controller(QObject *parent = Q_NULLPTR)
        : QObject(parent)
    {
        qDebug() << Q_FUNC_INFO;
    }

    ~Controller()
    {
        qDebug() << Q_FUNC_INFO;
    }

public slots:
    void put(const QString &msg)
    {
        qDebug() << msg;
    }
};

class Writer : public QObject
{
    Q_OBJECT

public:
    Writer(QObject *parent = Q_NULLPTR)
        : QObject(parent),
          m_timer(new QTimer(this))
    {
        qDebug() << Q_FUNC_INFO;
        connect(m_timer, &QTimer::timeout, this, &Writer::onSend);
    }

    ~Writer()
    {
        qDebug() << Q_FUNC_INFO;
    }

signals:
    void send(const QString &msg);
    void taskFinished();

public slots:
    void startSending()
    {
        m_timer->start(5);
    }

private slots:
    void onSend()
    {
        emit send(QString("Package %1").arg(m_pkg++));

        if (m_pkg == 100) {
            m_timer->stop();
            emit taskFinished();
        }
    }

private:
    QTimer *m_timer;
    int m_pkg = 1;
};

#endif // CONTROLLER_H

main.cpp

#include <QThread>
#include <QApplication>

#include "controller.h"

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    Controller ctrl;

    QThread pThread;
    Writer pWriter;
    pWriter.moveToThread(&pThread);

    QObject::connect(&pThread, &QThread::started,    &pWriter,    &Writer::startSending);
    QObject::connect(&pWriter, &Writer::send,         &ctrl,      &Controller::put, Qt::QueuedConnection);
    QObject::connect(&pWriter, &Writer::taskFinished, [&a, &pThread](){
        pThread.quit();
        a.quit();
    });

    pThread.start();

    return a.exec();
}

UPD: timer лучше не создавать в конструкторе, но для данного случая и так норм.

RazrFalcon ★★★★★ ()
Последнее исправление: RazrFalcon (всего исправлений: 1)
Ответ на: комментарий от PETER

Я честно попробовал осилить твой код, но ясно одно: если ты продолжишь кодить в таком стиле, и так работать с потоками - твои макароны будут глючить и падать или что-то не вызывать.

Года 4 назад я так же неряшливо работал с потоками, не понимая сути их правильного использования в Qt совместно с сигналами-слотами и получал тонны нелепых ситуаций несрабатывания сигналов, дедлоков и тому подобного...

На ЛОРе была тема, не могу найти но там подробно было, а пока вот тебе статья: https://habrahabr.ru/post/150274/ - пока я так не начал делать, потоки вызывали страдания.

I-Love-Microsoft ★★★★★ ()
Ответ на: комментарий от asaw

Спасибо, сработало:) контроллер был без очереди сообщений

PETER ★★ ()
Ответ на: комментарий от PETER

Добавил ProcessEvents? Или что? Явно что-то делаешь не так, где же event loop. Странный способ работы с Qt...

I-Love-Microsoft ★★★★★ ()
Последнее исправление: I-Love-Microsoft (всего исправлений: 1)
Ответ на: комментарий от I-Love-Microsoft

добавил

QThread thr( &a );
ctrl.moveToThread( &thr );


ничего странного - графики нет, нужно из разных потоков писать в контроллер данные, а уж дальше он сам ...
PETER ★★ ()
    QObject::connect(pThread, &QThread::finished,   pWriter,    &QObject::deleteLater );
    QObject::connect(pThread, &QThread::finished,   pThread,    &QObject::deleteLater );
    QObject::connect(pWriter, &Writer::send,        &ctrl,      &Controller::put, Qt::BlockingQueuedConnection/*Qt::QueuedConnection*/ );
    QObject::connect(pThread, &QThread::started,    pWriter,    &Writer::write );

Обращу внимание на другой момент. Метод connect() возвращает значение. А значит это значение надо проверять. Соблюдение технологической культуры - это важно.

pathfinder ★★★ ()
Ответ на: комментарий от pathfinder

У него ж «новый синтаксис», если уж скомпилилось то точно соединится и заработает, разве не?

I-Love-Microsoft ★★★★★ ()
Ответ на: комментарий от asaw

Ты должен периодически вызывать в нем

И лучше писать так чтобы ничего не вызывать, потому что это костыль.

anonymous ()
Ответ на: комментарий от I-Love-Microsoft

Нет, скомпилится и не будет работать если в качестве объектов передаются нульпойнтеры ☺

kuzulis ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.