保持活动的线程(Qt)

时间:2014-05-08 06:44:18

标签: c++ multithreading qt

我正在尝试纠正大型程序的内存泄漏和未停止的线程。我知道我有一些,但我不确定如何正确识别和杀死它们,所以我开始玩一些规范的例子,我已经有了这些。

首先,我尝试了最简单的事情:

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中的步骤,但也许我错过了一些东西。

1 个答案:

答案 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);
  }
};