当 Qt Slot 位于通过 std::async 创建的线程上时,它不会被调用
Qt Slot is not called when it lives on a thread created via std::async
我想创建一个 Qt 小部件,它通过信号/槽系统与不同线程上的其他 classes 通信。接收对象是在 运行 通过 std::async 的函数中创建的。
问题是:如果小部件发出信号,则不会调用另一个线程上的插槽。
我的例子:
我创建了 Class MainWindow,它派生自 QMainWindow 并将在主线程上运行。 class 接收器是在通过 std::async 调用的函数中创建的,并且有一个线程应该向控制台打印一些内容。
我通过将信号连接到同一线程上的另一个插槽来测试信号是否发出,效果很好。
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();
}
经过一些研究,我最强烈的猜测是,由 std::async 启动的线程没有 Qt 事件循环,因此不会到达处理发布事件(发出)的地步。我将 main 更改为使用 QtConcurrent::run 但它也没有用。
编辑
这是我对 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();
}
如果您想处理跨线程槽调用,您的线程中需要一个 运行 事件循环。
auto future = QtConcurrent::run( [&myWidget](){
StartAndConnect(myWidget);
QEventLoop e;
e.exec();
});
但我建议使用 QThread
,因为在您的情况下很明显。 Qt 有一个 very good documentation,描述了你的情况。
我想创建一个 Qt 小部件,它通过信号/槽系统与不同线程上的其他 classes 通信。接收对象是在 运行 通过 std::async 的函数中创建的。 问题是:如果小部件发出信号,则不会调用另一个线程上的插槽。
我的例子:
我创建了 Class MainWindow,它派生自 QMainWindow 并将在主线程上运行。 class 接收器是在通过 std::async 调用的函数中创建的,并且有一个线程应该向控制台打印一些内容。
我通过将信号连接到同一线程上的另一个插槽来测试信号是否发出,效果很好。
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();
}
经过一些研究,我最强烈的猜测是,由 std::async 启动的线程没有 Qt 事件循环,因此不会到达处理发布事件(发出)的地步。我将 main 更改为使用 QtConcurrent::run 但它也没有用。
编辑
这是我对 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();
}
如果您想处理跨线程槽调用,您的线程中需要一个 运行 事件循环。
auto future = QtConcurrent::run( [&myWidget](){
StartAndConnect(myWidget);
QEventLoop e;
e.exec();
});
但我建议使用 QThread
,因为在您的情况下很明显。 Qt 有一个 very good documentation,描述了你的情况。