简体   繁体   中英

Qt Slot is not called when it lives on a thread created via std::async

I wanted to create a Qt widget which communicates with other classes on different threads via the signal / slot system. The recieving Objects are created in a Function wich is run via std::async. The problem is: If the widget emits a signal the slot on the other thread is not called.

My Example:

I created the Class MainWindow which derives from QMainWindow and will live on the main thread. The class Reciever is created in a function which is called via std::async, and has a thread which should print something to the console.

I tested if the signal is emitted by connecting it to another slot on the same thread which works fine.

MainWindow.hpp

#pragma once

#include <QMainWindow>

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
     explicit MainWindow(QWidget *parent = 0);

signals:
    void send();

private slots:
    void buttonClicked();
    void recieve();
};

MainWindow.cpp

#include "MainWindow.hpp"
#include <iostream>

#include <QPushButton>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent)
{
    QPushButton* start = new QPushButton("Start");
    setCentralWidget(start);
    start->show();

    connect(start, SIGNAL(clicked(bool)), this, SLOT(buttonClicked()));
    connect(this, SIGNAL(send()), this, SLOT(recieve()));
}

void MainWindow::buttonClicked()
{
    std::cout << "MainWindow::buttonClicked()\n";
    emit send();
}

void MainWindow::recieve()
{
    std::cout << "MainWindow::recieve()\n";
}

Reciever.hpp

#include <QObject>

class Reciever : public QObject
{
    Q_OBJECT
public:
    Reciever(QObject *parent = 0);

public slots:
    void recieve();
};

Reciever.cpp

#include "Reciever.hpp"

#include <iostream>

Reciever::Reciever(QObject *parent) : QObject(parent)
{
    std::cout << "Reciever()" << std::endl;
}

void Reciever::recieve()
{
    std::cout << "Reciever::recieve()" << std::endl;
}

main.cpp

#include "MainWindow.hpp"
#include "Reciever.hpp"
#include <QApplication>

#include <future>

void StartAndConnect(MainWindow &widget)
{
    Reciever* rec = new Reciever();

    QObject::connect(&widget, SIGNAL(send()), rec, SLOT(recieve()));
}

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

    QApplication app(argc, argv);

    MainWindow myWidget;

    myWidget.show();

    auto future = std::async(std::launch::async, [&myWidget](){
        StartAndConnect(myWidget);
    });

    app.exec();

    future.wait();
}

After some research my strongest guess was, that the thread launched by std::async does not has a Qt event-loop and thus will not come to a point where the posted event (emit) is processed. I changed the main to use QtConcurrent::run but it also did not work.

EDIT

Here my try with QtConcurrent:

main2.cpp

#include "MainWindow.hpp"
#include "Reciever.hpp"
#include <QApplication>

#include <future>
#include <QtConcurrent>

void StartAndConnect(MainWindow &widget)
{
    Reciever* rec = new Reciever();

    QObject::connect(&widget, SIGNAL(send()), rec, SLOT(recieve()));
}

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

    QApplication app(argc, argv);

    MainWindow myWidget;

    myWidget.show();

    auto future = QtConcurrent::run( [&myWidget](){
    StartAndConnect(myWidget);
    });

    app.exec();

    future.waitForFinished();
}

You need a running event loop in your thread, if you want to process cross-thread slot calls.

auto future = QtConcurrent::run( [&myWidget](){
StartAndConnect(myWidget);
QEventLoop e;
e.exec();
});

But I recomend to use QThread , because in your case it is obvious. Qt has a very good documentation , that describes your case.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM