1

我有一个 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 应该受到责备。

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

4

1 回答 1

0

首先你做错了!首先修复你的线程

// 编辑根据我自己对这种模式的经验,我知道它可能会导致许多不清楚的崩溃。我会从清除这件事开始,因为它可能会理顺一些事情并使发现问题变得清晰。另外我不知道您如何调用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 的每次调用都会产生崩溃。

这是可能的情况之一。这就是为什么您不会每次都崩溃的原因。

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

于 2012-06-07T13:19:37.270 回答