![](/img/trans.png)
[英]Qt/C++ memory leak with QThread and QPainter::drawText()
[英]QThread is creating a memory leak
经过大量测试并更改了我的QT应用程序后,Visual Leak Detector识别出了令人讨厌的泄漏源(8个字节)。 VLD报告说,除QThread*
指针外,QT应用程序是干净的。
一些实施背景:Jeffrey Holmes将应用程序建模为解决方案的混合体, 使用Qt批量下载网页 。 感谢Jeffrey提早提供解决方案!
问题:
为什么工作线程完成工作后QThread*
不会自我破坏?
工作完成后,如何强制QThread*
删除线程和辅助对象?
QThread
应该以不同的方式实现吗?
码:
void vqMDIChildDialog::processWorkQueue(bool bIsBC)
{
if (m_listOfTables.isEmpty() && currentReplicationThreads == 0)
{
}
else if (!m_listOfTables.isEmpty())
{
for (int i = 0; i < maxReplicationThreads && !m_listOfTables.isEmpty();i++)
{
QThread *thread = new QThread;
QPointer<vcSharedDataQt> worker = new vcSharedDataQt();
worker->moveToThread(thread);
QString tmpTableName (m_listOfTables.dequeue());
worker->setParentObject(this);
//
// set properties on the worker object.
//
connect(thread, SIGNAL(started()), worker, SLOT(process()));
connect(worker, SIGNAL(finished()), thread, SLOT(quit()));
connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater()));
connect(thread, SIGNAL(finished()), thread,SLOT(deleteLater()));
connect(worker,
SIGNAL(updateMessageFromThread( const QString&,
const QString&,
const QString&,
const QString&,
const QString&,
const QString&,
const QString&)),
this,
SLOT(UpdateStatusBarFromThread( const QString&,
const QString&,
const QString&,
const QString&,
const QString&,
const QString&,
const QString&)));
thread->setObjectName(worker->getUniqueKey());
thread->start();
currentReplicationThreads ++;
}
}
}
Stack不允许我回答这个问题,所以:
该功能受QMutex
保护:
mutex.lock();
processWorkQueue();
mutex.unlock();
这导致内存泄漏。 QThread
显然无法在辅助线程完成时销毁。 我删除了互斥锁,并且VLD报告QThread
没有内存泄漏。
QThread
并不真正知道何时完成工作。 您可以通过考虑如何实现此问题来回答自己的问题。
它的run()
方法只是旋转事件循环。 由于所有事件循环都可以知道是否有任何事件发布到其上,因此,您可以合理地实现的唯一条件是,在没有其他事件发生时退出线程。 这将使线程立即退出,因此根本没有帮助。
也许您希望在没有更多以该线程为线程的QObject
时终止该线程。 当然可以在QThread
中将其实现为可选行为,但是我不知道这是否会被接受。 它一定不是默认行为,因为在许多情况下,不断销毁和重新创建线程简直是浪费的-人们可能想保留一个没有对象的线程。
最终只有您知道线程的工作时间。 您的工作程序对象可以调用thead()->quit()
或完成后发出信号-就像您已经做过的那样。
由于线程是可重新启动的,因此在完成工作后, QThread
无法销毁自己。 您可以完全控制线程的生存期,因此您可以肯定地在线程工作完成后销毁它,而您已经这样做了,只有错了。
您的问题实际上是您希望事情发生的顺序。 deleteLater
操作由事件循环执行。 如果线程的事件循环未运行,则deleteLater
是NO-OP。
因此,首先,应进行连接,以使它们形成只能以明确定义的顺序执行的级联:
connect(thread, SIGNAL(started()), worker, SLOT(process())); connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater())); connect(worker, SIGNAL(destroyed()), thread, SLOT(quit())); connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
然后,您必须确保运行processWorkQueue
方法的线程未被阻塞,并且有机会继续其事件循环。 这个事件循环将处理线程的删除。
正如AlexP所指出的那样,这在Qt 4.7或更早的版本中不起作用,因为所有这些版本在QThread的实现中均存在错误。 “ QThread的行为已更改”是委婉说法,因为“有一个丑陋的错误终于解决了”。
您的连接过于冗长。 您可以从签名中删除空格和引用/ const-reference。 如果是this
则第三个参数也是可选的。 它应该看起来像:
connect(worker, SIGNAL(updateMessageFromThread(QString,QString,QString,QString, QString,QString,QString)), SLOT(updateStatusBarFromThread(QString,QString,QString,QString, QString,QString,QString)));
答案:
QThread*
不会自我破坏? 因为有多种使用QThread
,其中在工作人员完成后至少必须有一种能够查询线程状态或类成员的方法。 此外,线程可能会重新启动。
QThread*
删除线程和辅助对象? finished
信号应该足以让您调用删除两者的插槽。
QThread
应该以不同的方式实现吗? 针对不同情况有不同的实现。 http://qt-project.org/doc/qt-5.0/qtcore/thread-basics.html
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.