QtConcurred 生成的线程与主线程具有相同的 ID
QtConcurred spawned threads have same ID as main thread
在我的桌面软件中,我从主 window 启动了几个 QtConcurrent 线程。我用 QThread::currentThreadId()
检查了线程 ID,发现它们与 GUI 线程具有相同的 ID。做了一些实验,发现罪魁祸首是 waitForFinished()
方法。但是以一种很奇怪的方式...
我编写了一个最小测试,在单击按钮时生成 qtconcurrent。 运行 方法更新旋转框上的计数器。
#include "MainWindow.h"
#include "ui_MainWindow.h"
#include <QDebug>
#include <QThread>
#include <qtconcurrentrun.h>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui_(new Ui::MainWindow)
, cnt_(0)
{
ui_->setupUi(this);
connect(this, &MainWindow::setSpinBoxValue, ui_->spinBox, &QSpinBox::setValue);
qDebug() << "MainWindow() thread ID: " << QThread::currentThreadId();
}
MainWindow::~MainWindow()
{
qDebug() << "~MainWindow() thread ID: " << QThread::currentThreadId();
delete ui_;
}
void MainWindow::on_pushButton_clicked()
{
qDebug() << "on_pushButton_clicked() thread ID: " << QThread::currentThreadId();
QFuture<void> th = QtConcurrent::run(this, &MainWindow::updateValue);
// TEST MADE ENABLING/DISABLING THE FOLLOWING LINE
th.waitForFinished();
}
void MainWindow::updateValue()
{
qDebug() << "updateValue() thread ID: " << QThread::currentThreadId();
emit setSpinBoxValue(++cnt_);
}
如果我 remove/comment th.waitForFinished()
行调试输出显示点击线程和并发线程的不同 ID,正如预期的那样:
14:38:17: Debugging starts
MainWindow() thread ID: 0x1ad0
on_pushButton_clicked() thread ID: 0x1ad0
updateValue() thread ID: 0xc40
on_pushButton_clicked() thread ID: 0x1ad0
updateValue() thread ID: 0xc40
on_pushButton_clicked() thread ID: 0x1ad0
updateValue() thread ID: 0xc40
~MainWindow() thread ID: 0x1ad0
14:38:27: Debugging has finished
如果我等待线程终止(th.waitForFinished()
调用),第一次并发 运行s 在新线程中,然后它 运行s 在主 GUI 线程上所有连续调用
14:40:23: Debugging starts
MainWindow() thread ID: 0x764
on_pushButton_clicked() thread ID: 0x764
updateValue() thread ID: 0x83c
on_pushButton_clicked() thread ID: 0x764
updateValue() thread ID: 0x764
on_pushButton_clicked() thread ID: 0x764
updateValue() thread ID: 0x764
~MainWindow() thread ID: 0x764
14:40:35: Debugging has finished
为什么会这样?
我想这与等待是在主线程中完成有关。但是一旦等待完成,软件就可以自由创建一个新线程,所以我不知道为什么会这样。
我正在研究 Windows 10,Qt 5.15.2 MSVC2019 x64
这似乎是一种意外行为,因为它没有记录在案。也许理解问题原因的关键是默认情况下 QtConcurrent::run()
使用 QThreadPool::globalInstance()
但如果创建了不同的 QThreadPool 则不会观察到此问题:
void MainWindow::on_pushButton_clicked()
{
qDebug() << "on_pushButton_clicked() thread ID: " << QThread::currentThreadId();
QThreadPool pool;
QFuture<void> th = QtConcurrent::run(&pool, this, &MainWindow::updateValue);
// TEST MADE ENABLING/DISABLING THE FOLLOWING LINE
th.waitForFinished();
}
我在 Qt bugreports 上聊过这个话题。
虽然没有记录,但注意到的行为是预期的。总结:
QtConcurrent::run()
被称为
waiForFinished()
被称为
- 主线程需要停止等待其他线程完成
- 但是当行为与执行函数调用完全一样时,为什么还要费心创建一个新线程呢?
=> Qt在一个函数调用中自动转换
QtConcurrent::run()
(在主线程中执行)
如果创建多个线程就不会发生这种情况
QFuture<void> th[2];
for(unsigned int i = 0; i < 2; i++)
th[i] = QtConcurrent::run(this, &MainWindow::updateValue, i);
for(unsigned int i = 0; i < 2; i++)
th[i].waitForFinished();
在这种情况下,Qt 不能在函数调用中转换QtConcurrent::run()
,否则2 个线程不会运行 并行。因此将创建 2 个新线程(两个 updateValue()
函数将在 ID 与主线程 ID 不同的线程中 运行)。
要解决单线程问题,请使用 QFutureWatcher
而不是 waitForFinished()
,它会在线程终止时发出信号;主线程不会被锁定(当插槽连接到信号时,主线程将 return 锁定),每次 QtConcurrent::run()
调用都会创建新线程。
在我的桌面软件中,我从主 window 启动了几个 QtConcurrent 线程。我用 QThread::currentThreadId()
检查了线程 ID,发现它们与 GUI 线程具有相同的 ID。做了一些实验,发现罪魁祸首是 waitForFinished()
方法。但是以一种很奇怪的方式...
我编写了一个最小测试,在单击按钮时生成 qtconcurrent。 运行 方法更新旋转框上的计数器。
#include "MainWindow.h"
#include "ui_MainWindow.h"
#include <QDebug>
#include <QThread>
#include <qtconcurrentrun.h>
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui_(new Ui::MainWindow)
, cnt_(0)
{
ui_->setupUi(this);
connect(this, &MainWindow::setSpinBoxValue, ui_->spinBox, &QSpinBox::setValue);
qDebug() << "MainWindow() thread ID: " << QThread::currentThreadId();
}
MainWindow::~MainWindow()
{
qDebug() << "~MainWindow() thread ID: " << QThread::currentThreadId();
delete ui_;
}
void MainWindow::on_pushButton_clicked()
{
qDebug() << "on_pushButton_clicked() thread ID: " << QThread::currentThreadId();
QFuture<void> th = QtConcurrent::run(this, &MainWindow::updateValue);
// TEST MADE ENABLING/DISABLING THE FOLLOWING LINE
th.waitForFinished();
}
void MainWindow::updateValue()
{
qDebug() << "updateValue() thread ID: " << QThread::currentThreadId();
emit setSpinBoxValue(++cnt_);
}
如果我 remove/comment th.waitForFinished()
行调试输出显示点击线程和并发线程的不同 ID,正如预期的那样:
14:38:17: Debugging starts
MainWindow() thread ID: 0x1ad0
on_pushButton_clicked() thread ID: 0x1ad0
updateValue() thread ID: 0xc40
on_pushButton_clicked() thread ID: 0x1ad0
updateValue() thread ID: 0xc40
on_pushButton_clicked() thread ID: 0x1ad0
updateValue() thread ID: 0xc40
~MainWindow() thread ID: 0x1ad0
14:38:27: Debugging has finished
如果我等待线程终止(th.waitForFinished()
调用),第一次并发 运行s 在新线程中,然后它 运行s 在主 GUI 线程上所有连续调用
14:40:23: Debugging starts
MainWindow() thread ID: 0x764
on_pushButton_clicked() thread ID: 0x764
updateValue() thread ID: 0x83c
on_pushButton_clicked() thread ID: 0x764
updateValue() thread ID: 0x764
on_pushButton_clicked() thread ID: 0x764
updateValue() thread ID: 0x764
~MainWindow() thread ID: 0x764
14:40:35: Debugging has finished
为什么会这样?
我想这与等待是在主线程中完成有关。但是一旦等待完成,软件就可以自由创建一个新线程,所以我不知道为什么会这样。
我正在研究 Windows 10,Qt 5.15.2 MSVC2019 x64
这似乎是一种意外行为,因为它没有记录在案。也许理解问题原因的关键是默认情况下 QtConcurrent::run()
使用 QThreadPool::globalInstance()
但如果创建了不同的 QThreadPool 则不会观察到此问题:
void MainWindow::on_pushButton_clicked()
{
qDebug() << "on_pushButton_clicked() thread ID: " << QThread::currentThreadId();
QThreadPool pool;
QFuture<void> th = QtConcurrent::run(&pool, this, &MainWindow::updateValue);
// TEST MADE ENABLING/DISABLING THE FOLLOWING LINE
th.waitForFinished();
}
我在 Qt bugreports 上聊过这个话题。
虽然没有记录,但注意到的行为是预期的。总结:
QtConcurrent::run()
被称为waiForFinished()
被称为- 主线程需要停止等待其他线程完成
- 但是当行为与执行函数调用完全一样时,为什么还要费心创建一个新线程呢?
=> Qt在一个函数调用中自动转换
QtConcurrent::run()
(在主线程中执行)
如果创建多个线程就不会发生这种情况
QFuture<void> th[2];
for(unsigned int i = 0; i < 2; i++)
th[i] = QtConcurrent::run(this, &MainWindow::updateValue, i);
for(unsigned int i = 0; i < 2; i++)
th[i].waitForFinished();
在这种情况下,Qt 不能在函数调用中转换QtConcurrent::run()
,否则2 个线程不会运行 并行。因此将创建 2 个新线程(两个 updateValue()
函数将在 ID 与主线程 ID 不同的线程中 运行)。
要解决单线程问题,请使用 QFutureWatcher
而不是 waitForFinished()
,它会在线程终止时发出信号;主线程不会被锁定(当插槽连接到信号时,主线程将 return 锁定),每次 QtConcurrent::run()
调用都会创建新线程。