C++ 保持活动状态的线程(Qt)
我正在尝试纠正一个大型程序的内存泄漏和未停止的线程。我知道我有一些,但我不确定如何正确识别和杀死它们,所以我开始玩一些经典的例子,我已经有了 首先,我尝试了最简单的方法:C++ 保持活动状态的线程(Qt),c++,multithreading,qt,C++,Multithreading,Qt,我正在尝试纠正一个大型程序的内存泄漏和未停止的线程。我知道我有一些,但我不确定如何正确识别和杀死它们,所以我开始玩一些经典的例子,我已经有了 首先,我尝试了最简单的方法: int main(int argc, char *argv[]) { QCoreApplication a(argc, argv); return a.exec(); } 这使我在任务管理器中有一(1)个正在运行的线程 int main(int argc, char *argv[]) { QCoreA
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();
}
这一个在启动辅助线程之前给我1,然后在线程实际启动之前给我2(process
被调用),然后给我3,直到捕捉到singleShot
信号并删除辅助线程,然后再给我2。所以我有点松了
这是工作指南的代码:
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) { }
平台是Qt5.2.1,带有mingw48_32编译器
我想我正在按照中的步骤进行操作,但可能我遗漏了什么。您对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);
}
};
第一个线程用于
main
,第二个线程用于WorkerOne
,但谁在这里创建了第三个线程?我测试了您的代码,当我将单次触发计时器的超时从1000
更改为2000
时,线程数从3
变为预期的2
。出于某种原因,QTimer::singleShot
正在启动第三个线程,但不是在我将超时增加到2000时。我不知道那里发生了什么。实际上它应该被删除,因为文档中说明了QThread::finished
信号:。@thuga这里它根本不适用,因为有一个从finished()
到deleteLater()
的直接连接,它将被线程的事件循环拾取。我误读了代码。在其他工人仍在工作的更一般情况下,我不会退出QCoreApplication。删除该连接的代码永远不会调用WorkerOne
的析构函数,并且需要从&thread
的finished()
发送信号到WorkerOne
的deleteLater()
。是吗?@dmcontador这些都是局部变量,它们没有分配到堆上。只要main()
返回,就可以保证WorkerOne
和QThread
都会按以下顺序被破坏。在这些对象中的任何一个上调用deleteLater
,实际上都是一个错误。一般来说,除非需要,否则不要在堆上分配东西。对于QObject
类型的类成员,欢迎将它们作为直接类成员,而不是指针成员。@KubaOber将在主线程或新线程中调用processChunk
(因为worker.start
在worker.moveToThread
之前启动)?