【问题标题】:abort reply crashes with access violation中止回复因访问冲突而崩溃
【发布时间】:2012-05-13 12:03:26
【问题描述】:

我有一个大问题,我实际上认为我解决了它。我有一个使用 QNetworkAccessManager 的应用程序。这个 QNAM 位于一个类中。当我在这个 QNAM 上执行请求时,所有这些请求都在一个包装器中完成,该包装器包含回复并对其进行重试逻辑

例如,如果我在构造函数中有一个 putBlob(它继承自 baseRequest),我会传递一个对 QNAM 的引用。我在它上面执行请求并保存一个指向回复的指针。然后回复将是包装子,因此 QNAM 不再拥有它的所有权。包装器是持有 QNAM 的原始类的子级。

类有一个 QNAM,和子“putBlobRequest”,它有子“QNetworkReply*”

现在的问题是当用户想要取消时,应该删除主对象及其中的所有内容。包装器还应该中止它的 QNetworkReply 并断开连接(这样它就不会调用 finish())

我在 baseRequest 上的析构函数(包含 QNetworkReply 并且是它的父级)如下所示:

if(_reply) {
    if(_reply->isRunning()) {
        _reply->disconnect(SIGNAL(finished()));
        _reply->disconnect(SIGNAL(uploadProgress(qint64, qint64)));
        _reply->abort();
    }
}

当包装器在持有它的类中被杀死时,删除就完成了。(对吗?)

这有时有效,但有时我会遇到巨大的访问冲突,并且所有内容都因以下调用堆栈而崩溃:

QtCored4.dll!QObject::disconnect(const QObject * sender, const char * signal, const QObject * receiver, const char * method)  Line 2891 + 0x8 bytes C++
QtNetworkd4.dll!QNetworkReplyImpl::abort()  Line 874 + 0x18 bytes   C++
FrameworkAzure.dll!BaseRequest::~BaseRequest()  Line 129 + 0xa bytes    C++
FrameworkAzure.dll!PutBlobRequest::~PutBlobRequest()  Line 24 + 0x5e bytes  C++
FrameworkAzure.dll!PutBlobRequest::`scalar deleting destructor'()  + 0xb bytes  C++
FrameworkAzure.dll!AzureBlobStorageProvider::~AzureBlobStorageProvider()  Line 41 + 0xa8 bytes  C++

所以首先调用 abort(),它调用以下内容:

if (d->outgoingData)
    disconnect(d->outgoingData, 0, this, 0); <--- we go in here

这将我带到 QOBject.cpp 中的第 2891 行:

const QMetaObject *smeta = sender->metaObject(); 

它因错误而崩溃的地方:

CloudSync.exe 中 0x66c2c490 (QtCored4.dll) 处的未处理异常:0xC0000005:访问冲突读取位置 0xdddddddd。

地址“0xdddddddd”是“发送者”。

为什么发送者对象不可读?我究竟做错了什么?请帮忙!

编辑:

也试过了:

if(_reply) {
    if(_reply->isRunning()) {
        disconnect(_reply, SIGNAL(finished()), this, SLOT(handleFinishedRequest()));
        _reply->abort();

    }
}

我还断开了导出的 putBlob 中的 uploadProgress。也尝试过不断开连接,但同样的问题是违反了“发件人”

【问题讨论】:

  • 即使注释掉disconnect() 的两行,它会崩溃吗?
  • 是的,但是一个不同的崩溃 cus 然后它发送一个信号,表明将被正在删除的对象咳嗽
  • _reply 是 QPointer 吗?另外,您在哪里更改 QNetworkReply 的所有权?

标签: c++ qt access-violation qnetworkaccessmanager


【解决方案1】:

就我而言,我有一个如下的replyFinished功能:

void MyClass::replyFinished(QNetworkReply *reply)
{
   ...
   delete reply;
}

在我的程序中,这个函数是通过 QNetworkAccessManager 连接的,因此即使我调用了disconnect(reply, ...),回复也不会与它断开连接。命令abort会触发这个函数(replyFinished)并删除回复,我再删除一次(通过reply->deleteLater())并导致崩溃。

解决方案:添加属性进行回复并检查。

disconnect(reply, nullptr, this, nullptr);
reply->setProperty("deleting", 1);
reply->abort();
...
void MyClass::replyFinished(QNetworkReply *reply)
{
   if (reply->property("deleting").isValid())
      return;

   ...
   delete reply;
}

【讨论】:

    【解决方案2】:

    锁定 _reply 的 (QNetworkReply) 销毁,并且在此之后不执行触及它的工作流(_reply 的销毁,即)。当问题发生时,您的 _reply 已被删除并出现乱码。

        bool bReplyDestroyed = false;
    
        connect(_reply, &QObject::destroyed, [=](){
           // set something indicative of _reply no longer usable
           bReplyDestroyed = true;
        });
    
        if(!bReplyDestroyed) {
          if(_reply->isRunning()) {
            disconnect(_reply, SIGNAL(finished()), this, SLOT(handleFinishedRequest()));
            _reply->abort();
          }
        }
    

    【讨论】:

    • 这可能行得通 :) 距离我完成那个项目已经太多年了,我不记得我最终是如何解决它的。我确实很想念 Qt。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-05
    • 2016-06-14
    • 1970-01-01
    相关资源
    最近更新 更多