我有一个库,它在单独的std :: thread中工作。该库的工作原理如下。在按钮上单击我调用库的对象方法,该方法启动长时间的任务。调用此方法时,可以提供进度回调,库会定期调用该回调以通知当前正在执行的操作。
回调定义为
var list = new List<Something>
{
new Something()
{
Tags = new HashSet<string>() { "tag1", "tag2" }
},
new Something()
{
Tags = new HashSet<string>() { "tag3", "tag4" }
}
};
var searchList = new List<string> { "tag1", "tag4"};
var result = list.Where(x => x.Tags.Any(y => searchList.Contains(y)));
我写了非常简单的例子,描述了我的情况。这是它:
typedef std::function <void (const std::string &message)> Callback;
它依赖于向textEdit追加消息。如果我评论这一行都没问题,qDebug正确打印我的消息。
如果不是附加消息来登录lambda我发出信号并在相应的插槽中附加,它也可以正常工作:
class FakeLibrary
{
typedef std::function<void (const std::string &str)> Callback;
public:
FakeLibrary() {}
void run(Callback callback)
{
auto lambda = [this, callback]() {
callback("blahblah");
};
std::thread thread(lambda);
thread.detach();
}
};
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
FakeLibrary *library_obj = new FakeLibrary;
connect(ui->pushButton, &QPushButton::clicked, [this, library_obj]() {
library_obj->run([this](const std::string &message) {
ui->textEdit->append(QString::fromStdString(message));
qDebug() << QString::fromStdString(message);
});
});
}
所以有人可以解释一下有什么区别以及为什么会出现这种情况?
答案 0 :(得分:2)
library_obj->run([this](const std::string &message) {
ui->textEdit->append(QString::fromStdString(message));
qDebug() << QString::fromStdString(message);
});
您传递了一个包含GUI对象操作的lambda函数。 不应该超出主线程。
如上所述,每个程序在启动时都有一个线程。这个 线程被称为&#34;主线程&#34; (也称为&#34; GUI线程&#34; in Qt应用程序)。 Qt GUI必须在此线程中运行。所有小部件和 几个相关的课程,例如QPixmap,不在中学工作 线程。辅助线程通常被称为&#34;工作者 螺纹&#34;因为它用于从主要卸载处理工作 线程。
第二个实际使用:
QMetaObject::Connection QObject::connect(const QObject *sender,
PointerToMemberFunction signal,
const QObject *receiver,
PointerToMemberFunction method,
Qt::ConnectionType type = Qt::AutoConnection)
http://doc.qt.io/qt-5/qobject.html#connect
最后一个参数的默认值是Qt::AutoConnection
,这使得GUI操作交叉线程成为可能。第一个直接调用该函数,与将Qt::ConnectionType
更改为Qt::DirectConnection
答案 1 :(得分:1)
您只能在主线程中访问GUI。这就是第一个例子失败的原因。
第二个例子有效,因为信号槽连接可以跨越线程边界(通过将事件发布到引擎盖下的目标对象的线程)。
您可以在Qt's threading documentation中阅读此内容,尤其是有关线程关联性和信号槽连接的部分。