LINUX.ORG.RU

[Qt,QThread] не работает connect


0

1

Есть программа на Qt, реализующая работу с последовательным портом (через библиотеку QSerialPort). Вся работа с портом вынесена в отдельный поток. Суть проблемы: в дочернем потоке в функции run() испускается сигнал, который присоединен к слоту в родительском потоке. В итоге слот не срабатывает.

Родительский поток:

class MainWindow: public QMainWindow {
Q_OBJECT
public:
  MainWindow::MainWindow() {
    thread = new MyThread();
    connect(thread,SIGNAL(datareaded()),this,SLOT(datareaded()));
  }
public slots:
  void datareaded() {
    std::cout << "slot" << std::endl;
  }
private:
  class MyThread *thread;
};

Поток работы с портом:

class MyThread : public QThread {
Q_OBJECT
public:
  MyThread() {}
signals:
  void datareaded();
protected:
  void run() {
    while(1) {
      std::cout << "signal" << std::endl;
      emit datareaded();
    }
  }
};

В итоге выводяться только «signal». Почему? Помогите, пожалуйста.


Ответ на: комментарий от rival

Я, к сожалению, пока не сильно понимаю в программировании, объясните, пожалуйста, подробнее. Я так понял, что в конструктор MyThread() нужно добавить moveToThread(this), однако, не заработало.

GSA
() автор топика
Ответ на: комментарий от GSA

Не понял вопроса.

Не приведен код с циклом обработки сообщений (event loop). А вдруг его нет? Можно только догадываться, что у нас в родительском потоке крутится гуй и этот родительский поток, после того как сделал все свои дела вошел в свой цикл обработки сообщений.

У меня другой вопрос. В приведенном коде только создание нити, а где её запуск? Где QThread::start()?

pathfinder ★★★★
()

треды не программировал. Но... могут ли разные потоки выводить в стдаут? Для гуевых программ гуи может быть только в одном треде.

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

QThread::start() я забыл здесь написать, но в программе он есть.

Я все делал по учебнику «Jasmin Blanchette C++ GUI Programming with Qt4», там про event loop ничего не сказано. Почему недостаточно связать сигнал и слот в разных потоках? В гугле сказано, что так можно.

GSA
() автор топика
Ответ на: комментарий от azure

А что если не зацикливать вызов сигнала, а вызвать его лишь раз? connect то ведь бывает отложенный.

В функции run() происходит чтение из порта и сигнал должен излучаться, если данные прочитаны, а слот должен их обработать. Пока код такой:

void MyThread::run() {
  unsigned char data;
  short count;
  while(!stopped) {
    if(serialport->waitForReadyRead(100)) {
      count = serialport -> read((char *)data,256);
      printf("Read %d bytes\n",count);
      emit datareaded();
    }
  }
  stopped = FALSE;
}

Я понимаю, что connect асинхронный, но слот должен срабатывать, хоть и позже.

GSA
() автор топика
Ответ на: комментарий от GSA
class Worker : public QObject {
    Q_OBJECT

    // ... 

signals:
    void dataRead(); // "readed" не является словом в ангельском языке, afaik

public slots:
    void doYourJobForChristSake() {
        if (running) return;
        running = true;
        unsigned char data;
        short count;
        while (running) {
            if (serialport->waitForReadyRead(100)) {
                count = serialport->read((char *)data, 256);
                printf("Read %d bytes\n", count);
                emit dataRead();
            }
        }
    }
};
class SomeObject : public QObject {
    Q_OBJECT

public:
    SomeObject(QObject *parent = 0) 
        : QObject(parent) 
    {
        connect(&worker, SIGNAL(dataRead()), SLOT(readData()));
        connect(this, SIGNAL(startWorker()), &worker, SLOT(doYourJobForChristSake()));
        worker.moveToThread(&thread);
        thread.start();
    }

signals:
    void startWorker();

private slots:
    void readData();

private:
    Worker worker;
    QThread thread;
};
rival ★★
()
Ответ на: комментарий от pathfinder

Если в потоке нет слотов и эмиттятся только сигналы - event loop не нужен. Должно всё работать. Можно принудительно указать тип коннекта пятым необязательным параметром connect - Qt::QueuedConnection для асинхронного вызова слота в принимающем потоке. Можно еще попробовать invokeMethod для вызова методов-слотов в другом потоке без использования connect.

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

event loop не нужен

Всмысле в отправляющем не нужен. А принимающим у ТС выступает основной поток с главным окном и виджетами. Там event loop есть.

Suigintou ★★★★★
()

Сделал ректальный вариант: в конструктор потока передается указатель на MainWindow и делается connect().

Некрасиво, неправильно, но работает.

GSA
() автор топика
Ответ на: комментарий от GSA
#include <QMainWindow>
#include <QThread>
#include <QDebug>
#include <QApplication>

class MyThread : public QThread {
    Q_OBJECT
public:
    MyThread() {}
signals:
    void datareaded();
protected:
    void run() {
        while(1) {
            qDebug() << "signal";
            emit datareaded();
        }
    }
};

class MainWindow: public QMainWindow {
    Q_OBJECT
public:
    MainWindow() {
        thread = new MyThread();
        connect(thread,SIGNAL(datareaded()),this,SLOT(datareaded()));
        thread->start();
    }
    public slots:
        void datareaded() {
            qDebug() << "slot";
        }
private:
    class MyThread *thread;
};

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);

    MainWindow window;
    window.show();
    
    return app.exec();
}

#include "main.moc"

Твой же код, у меня работает нормально, в том смысле, что и «signal» и «slot» выводятся.

anonymous
()

Используй Qt::DirectConnection, если в твоём потоке не крутится кутешный ивентлуп, и ты коннектишь слот объекта, который живёт в таком потоке, к сигналу объекта из другого потока.

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

Ну что я могу сказать? Ты, сраный быдлокодер, вместо того, чтобы учить основы и писать вменяемый код, изобретаешь костыли и потом голову ломаешь над тем, почему они не (всегда) работают.

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

Я согласен с этим, просто это моя первая программа на Qt. Я сюда и написал, что бы поучиться.

GSA
() автор топика
Ответ на: комментарий от GSA

Я сюда и написал, что бы поучиться.

Ну так и учись, зачем вот это:

Сделал ректальный вариант: в конструктор потока передается указатель на MainWindow и делается connect().

Некрасиво, неправильно, но работает.

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

Я же не написал, что я это так оставлю.

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