QtConcurrent::使用MainWindow功能运行,警告消息"QObject::setParent:
QtConcurrent::run with MainWindow function, warning message "QObject::setParent: Cannot set parent, new parent is in a different thread"
我正在尝试使用QtConcurrent::run来执行MainWindow类中的一个函数,以便UI在计算过程中保持响应。以下是我如何实现它:
void MainWindow::on_calculate_pb_clicked()
{
QFuture<void> future = QtConcurrent::run(this,&MainWindow::calculation);
}
void MainWindow::calculation()
{
progressBar->show();
loadMap();
integral.clear();
positions.clear();
offset.clear();
lines = 0;
for(int i=0;i<paths.size();i++)
{
if(i ==0)
{
lines = countNumberOfLines(paths.at(i));
}
double file = i+1;
ui->statusBar->showMessage(QString("Processing file %1 of %2").arg(file).arg(paths.size()));
calculateIntegral(paths.at(i));
offset.push_back(ui->tableWidget->item(i,1)->text().toDouble());
}
makePositionVector();
plotData(ui->customPlot);
ui->export_pb->setEnabled(true);
progressBar->hide();
ui->statusBar->showMessage("Done",3000);
}
void MainWindow::calculateIntegral(QString path)
{
QVector<double> mappeddata,tempdata;
mappeddata.resize(map.size());
tempdata.resize(numberofdetectors);
double currentLine = 0;
QFile File(path);
if(File.exists()==true){
File.open(QIODevice::ReadOnly);
QTextStream in(&File);
double val;
while(!in.atEnd())
{
for(int j = 0;j<numberofdetectors;j++)
{
in >> val;
tempdata[j]+=val;
currentLine++;
double progress = currentLine/lines*100;
progressBar->setValue(progress);
}
}
for(int i =0;i<map.size();i++)
{
mappeddata[i] = tempdata.at(map.at(i));
}
for(int k = 0;k<numberofdetectors; k++)
{
integral.push_back(mappeddata.at(k));
}
}
File.close();
}
它运行良好,UI响应灵敏,进度条更新正确,但在输出中,我多次收到错误"QObject::setParent:无法设置父级,新的父级在不同的线程中",来自循环中执行的东西。
有什么想法导致了这种情况,或者对更好地实现QtConcurrent::run的建议吗?
感谢
您不能从工作线程中接触任何Qt提供的QWidget
对象,因为它们的大多数方法都不是线程安全的。
相反,解决这一问题的方法是在工作线程中进行计算,然后向主线程提交更新状态的函数。有关详细信息,请参阅此答案。
然后你的代码会变成:
void MainWindow::calculation()
{
postToThread([this]{ progressBar->show(); });
loadMap();
integral.clear();
positions.clear();
offset.clear();
lines = 0;
for(int i=0;i<paths.size();i++)
{
if (i == 0)
lines = countNumberOfLines(paths.at(i));
auto file = i+1;
postToThread([this]{
ui->statusBar->showMessage(
tr("Processing file %1 of %2").arg(file).arg(paths.size()));
});
calculateIntegral(paths.at(i));
postToThread([this]{
offset.push_back(ui->tableWidget->item(i,1)->text().toDouble());
});
}
makePositionVector();
postToThread([this]{
plotData(ui->customPlot);
ui->export_pb->setEnabled(true);
progressBar->hide();
ui->statusBar->showMessage("Done",3000);
});
}
以类似的方式修改calculateIntegral
,但要确保不会过于频繁地发出进度更新。
还要确保UI代码不会在其他地方访问您从辅助程序更新的成员。这可能很难,因为您混合了UI和计算。相反,将工作者抽象到一个没有UI的QObject
,并通过指示进度/状态的信号将其与其他代码接口。您仍将在该对象中使用QtConcurrent::run
,但确保没有其他线程访问该对象的私有状态会变得更简单。
要将完成的结果从工作函数中推出,可以发出一个携带结果的信号。Data
类型的复制成本应该很低,例如,您可以使用QSharedData
/QSharedDataPointer
来实现它。或者你可以通过QSharedPointer
拿着它。
class Computation : public QObject {
Q_OBJECT
void work() {
Data data;
... // updates data
emit finished(data);
}
public:
Q_SLOT void compute() {
QtConcurrent::run(&Worker::work, this);
}
Q_SIGNAL void finished(Data data);
};
您也可以将结果存储在对象中,并注意在计算活动时不会访问这些结果:
class Computation : public QObject {
Q_OBJECT
bool m_active { false };
Data m_data;
void work() {
... // updates m_data
m_active = false;
}
public:
Q_SLOT void compute() {
m_active = true;
QtConcurrent::run(&Worker::work, this);
}
const Data & data() const {
Q_ASSERT(! m_active);
return m_data;
}
};
当然,如果将对data()
的引用存储在主线程中,然后调用compute()
,则会有未定义的行为,所以不要这样做。
如果任何数据类型是隐式共享容器,如QVector
或QString
,则应按值返回它们,并且任何访问都是线程安全的:
QVector<MyData> data() const {
Q_ASSERT(! m_active);
return m_data;
}
注意,QFile
是一个适当的C++类。当它被销毁时,它会释放所有持有的资源。手动关闭文件是不必要的:编译器应该在这里帮助你,这就是C++的对象模型与Java的对象模型相比的全部意义。
- 删除 QSharedPointer 指向的 QObject
- QObject::连接无法将信号连接到*this*对象的插槽
- 调试符号中缺少 QObject 类信息(编辑但存在其他 Qt 类)
- QML/C++/QObject Struct Copy
- QObject::d eleteLater在我的Qt测试中没有像预期的那样调用
- 具有 QObject 继承的单例 - Qt
- QObject::连接不起作用 - 使用函数语法找不到信号
- 是否可以在单独的线程中将 QObject 设置为 QML 上下文属性?
- 智能指针作为 QObject::d eleteLater() 的替代品
- Shiboken2 qobject.h:46:10:致命:找不到'QtCore/qobjectdefs.h'文件
- 在 dll 中为 qLibrary 编译 qobject 时出错
- 将复制构造函数设置为默认值在继承自 QObject 时不起作用
- 'char (*RtlpNumberOf(T (&)[N]))[N]':无法从"char *"
- 我应该使用多个角色还是一个角色,将实际属性推迟到将数据包装/公开为其属性的QObject
- Arduino IDE 错误 - 无法找到数字文字运算符"运算符""f900ff"
- 在另一个线程上发出 QObject 信号的正确方法?
- 为什么 QObject::d isconnect(const QMetaObject::Connection &connection) 采用 const 参数并打算修改它?
- "inline"、"constexpr"或"noexcept"
- "非静态数据成员之前需要构造函数" - 我是否使用"boost::variant"
- 我必须安装"libbitcoin-server"才能包含"bitcoin.hpp"