我正在尝试纠正大型程序的内存泄漏和未停止的线程。我知道我有一些,但我不确定如何正确识别和杀死它们,所以我开始玩一些规范的例子,我已经有了这些。
首先,我尝试了最简单的事情:
int main(int argc, char *argv[]) {
QCoreApplication a(argc, argv);
return a.exec();
}
这让我在任务管理器中运行了一(1)个运行线程。
int main(int argc, char *argv[]) {
QCoreApplication a(argc, argv);
WorkerOne *w = new WorkerOne();
QTimer::singleShot(3456, w, SLOT(stop()));
return a.exec();
}
这个在启动worker之前给我1,然后在线程实际启动时为2(process
被调用),然后是3,直到捕获singleShot
信号并删除工作人员然后再次2 。所以我在那里放松了。
这是WorkerOne
的代码:
WorkerOne::WorkerOne(QObject *parent)
: QObject(parent)
, m_stop(false) {
QThread* thread = new QThread;
this->moveToThread(thread);
connect(this, SIGNAL(error(QString)), this, SLOT(errorString(QString)));
connect(thread, SIGNAL(started()), this, SLOT(process()));
connect(this, SIGNAL(finished()), thread, SLOT(quit()));
connect(this, SIGNAL(finished()), this, SLOT(deleteLater()));
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
thread->start();
}
WorkerOne::~WorkerOne() {}
void WorkerOne::process() {
while(!m_stop) {
QEventLoop loop; QTimer::singleShot(1000, &loop, SLOT(quit())); loop.exec();
}
emit finished();
}
void WorkerOne::stop() {
m_stop = true;
}
void WorkerOne::errorString(QString err) { }
该平台是Qt 5.2.1,带有mingw48_32编译器。
我想我正在遵循threading howto from Maya Posch's blog中的步骤,但也许我错过了一些东西。
答案 0 :(得分:1)
您对worker对象的实现实际上是颠倒的。旋转事件循环是QThread
的工作。您的工作对象应该只是由插槽调用和传入事件驱动。处理繁忙循环习惯用法使用零长度计时器保持活动状态,同时允许事件循环接收事件并退出,而不需要额外的标记。
以下是如何操作:
class WorkerOne : public QObject {
Q_OBJECT
QBasicTimer m_timer;
void processChunk() {
...
}
void timerEvent(QTimerEvent * ev) {
if (ev->timerId() == m_timer.timerId()) processChunk();
}
public:
WorkerOne(QObject * parent = 0) : QObject(parent) {}
Q_SLOT void start() { m_timer.start(0, this); }
};
int main(int argc, char *argv[]) {
QCoreApplication a(argc, argv);
WorkerOne worker;
QThread thread;
thread.start();
worker.start();
worker.moveToThread(&thread);
a.connect(&thread, SIGNAL(finished()), SLOT(quit()));
QTimer::singleShot(3456, &thread, SLOT(quit()));
return a.exec();
}
当计时器超时时,线程的事件循环退出,线程结束,应用程序的事件循环退出,最后,线程和工作程序被销毁。
零长度计时器实际上不是一个计时器,只是一个成语,意思是:一旦输入事件循环就调用我,没有别的事可做。执行以下操作将是一个过早的悲观,因为通过事件循环每轮都有一个内存分配 - 不使用计时器会更糟糕!
class WorkerOne : public QObject {
Q_OBJECT
Q_INVOKABLE void processChunk() {
...
// A lame attempt to call ourselves again from the event loop.
// It works, but has lot more overhead than a zero-length timer!
QMetaObject::invokeMethod(this, "processChunk", Qt::QueuedConnection);
}
public:
WorkerOne(QObject * parent = 0) : QObject(parent) {}
Q_SLOT void start() {
QMetaObject::invokeMethod(this, "processChunk", Qt::QueuedConnection);
}
};