当从2个线程发出2个网络请求时,Qt应用程序崩溃

时间:2012-06-07 12:30:12

标签: qt networking qthread qnetworkaccessmanager

我有一个Qt应用程序,它在启动时从主线程启动两个线程。这两个线程都使用QNetworkAccessManager对象的不同实例发出网络请求。我的程序在大约50%的时间内都会崩溃,我不确定哪个线程崩溃了。

两个线程之间没有直接发生数据共享或信令。当某个事件发生时,一个线程向主线程发出信号,主线程又可以发出第二个线程的信号。但是,通过打印日志,我很确定在信令过程中不会发生崩溃。

两个线程的结构如下。除了URL等之外,线程之间几乎没有任何区别。

MyThread() : QThread() {
    moveToThread(this);
}

MyThread()::~MyThread() {
    delete m_manager;
    delete m_request;
}

MyThread::run() {
    m_manager = new QNetworkAccessManager();
    m_request = new QNetworkRequest(QUrl("..."));

    makeRequest();
    exec();
}

MyThread::makeRequest() {
    m_reply = m_manager->get(*m_request);
    connect(m_reply, SIGNAL(finished()), this, SLOT(processReply()));
    // my log line
}

MyThread::processReply() {
    if (!m_reply->error()) {
        QString data = QString(m_reply->readAll());
        emit signalToMainThread(data);
    }
    m_reply->deleteLater();
    exit(0);
}

现在奇怪的是,如果我没有启动其中一个线程,程序运行正常,或者至少在大约20次调用中不会崩溃。如果两个线程一个接一个地运行,程序不会崩溃。如果我同时启动和运行两个线程,程序只会在 一半 时崩溃。

我从日志中收集的另一个有趣的事情是,每当程序崩溃时,标记为my log line的行是两个线程都要执行的最后一行。所以我不知道哪个线程导致崩溃。但它让我怀疑QNetworkAccessManager在某种程度上应该受到指责。

我对导致崩溃的原因一无所知。我将不胜感激任何建议或指示。提前谢谢。

1 个答案:

答案 0 :(得分:0)

首先you're doing it wrong!首先修复线程

//编辑 根据我自己对这种模式的经验,我知道它可能导致许多不清楚的崩溃。我会从清除这个东西开始,因为它可能会使一些事情变得清晰,并使发现问题变得清晰。另外我不知道你如何调用makeRequest。还有关于QNetworkRequest。它只是一个数据结构,因此您不需要在堆上创建它。堆栈结构就足够了。你也应该记住(或以某种方式保护)覆盖m_reply指针。你不止一次打电话给makeRequest吗?如果这样做,则可能导致在上一个请求完成后删除当前处理的请求。

如果你两次调用makeRequest会发生什么:

  1. 第一次调用makeRequest会指定m_reply指针。
  2. 第二次调用makeRequest第二次指定m_reply指针(替换指定的指针但不删除指向的对象)
  3. 第二个请求首先完成,因此调用processReply。 deleteLater排在第二位
  4. eventloop中的某个地方第二个回复被删除,所以从现在起m_reply指针指向一些随机(已删除)的内存。
  5. 第一个回复结束,所以调用了另一个processReply,但它在m_reply上操作,指向垃圾,因此m_reply的每次调用都会导致崩溃。
  6. 这是可能的情景之一。这就是你每次都不会崩溃的原因。

    我不确定你为什么在回复结束时调用exit(0)。如果你使用多次makeRequest调用,这里也是不正确的。请记住,QThread是单个线程的接口,而不是线程池。因此,当线程实例仍在运行时,您无法在线程实例上第二次调用start()。此外,如果您要在入口点run()中创建网络访问管理器,则应在exec()后的同一位置删除它。请记住,exec()正在阻止,因此在线程退出之前不会删除对象。