QMutexLocker中的QThread ASSERT失败:“QMutex指针未对齐”,

时间:2012-02-27 00:25:09

标签: c++ qt qthread qnetworkaccessmanager

我试图创建一个将创建新线程的上传器,并且在每个线程中我都有一个QNetworkAccessManager。所有上传程序线程都引用了共享列表,并将使用开始和结束索引对其进行拆分。

上传器看起来像这样:

 class FileUploader : public QObject {
    Q_OBJECT

public:
    explicit FileUploader(QList<FileInfoWrapper> &fileList, const int start = 0, const int offset = 0, QObject *parent = 0);


    void uploadNext();

    QString containerName;

private:
    int start_, offset_, iterator_;
    QList<FileInfoWrapper> &fileList_;
    RestFileUploader *restFileUploader;

signals:
    void progressChangedAt(int row);
    void statusChangedAt(int row);
    void finished();

public slots:
    void init();

private slots:
    void setUploadProgress(qint64 tranfered);
    void handleRequestFinished(QNetworkReply* reply);
    void handleSslErros(QNetworkReply *reply, const QList<QSslError> &errors);
    void handleNetworkError(QNetworkReply::NetworkError error);

};

然后,在run()函数中,我创建了新的RestFileUploader(this)(几乎是一个创建自己的新QNetworkAccessManager(this)并在其上发出请求的对象),这样就不会在构造函数中创建任何内容(这将是导致它最终在主线程中?)。 run函数创建一个请求给QNetworkAccessManager,然后什么都不做,直到信号“完成(QNetworkReply)”然后我抓住下一个(依此类推,直到列表逐步通过)。

然后我在主应用程序中创建两个新线程,当我使用run()启动它们时,除了两个线程上的ID相同外,它的工作方式。如果我改为调用“start()”,它会崩溃: QObject:无法为位于不同线程中的父级创建子级。 (Parent是FileUploader(0x2580748),父线程是QThread(0x4fb2b8),当前线程是FileUploader(0x2580748)

BUT!就在我开始逐步浏览列表之前,我打印了threadId并且它们不再相同。

我做错了什么或者我应该这样做: http://labs.qt.nokia.com/2006/12/04/threading-without-the-headache/

编辑:

我更改了它并将run重命名为start并创建了这个包装器(我不再使用“this”调用NetworkAccessManager或RestFileUploader):

FileUploader *fileUploader = new FileUploader(fileList_, start, (offset == 0 ? (fileList_.count() - start) : offset));
QThread *fileUploaderThread = new QThread;
fileUploader->moveToThread(fileUploaderThread);

connect(fileUploader, SIGNAL(progressChangedAt(int)), model_, SLOT(reportProgressChanged(int)));
connect(fileUploader, SIGNAL(statusChangedAt(int)), model_, SLOT(reportStatusChanged(int)));

fileUploaderThread->start();
QMetaObject::invokeMethod(fileUploader, "init", Qt::QueuedConnection);

上传一个对象时,因为我只使用一个线程。但是,当我有更多的对象被分割时,应用程序残忍地崩溃了这个错误消息:

ASSERT failure in QMutexLocker: "QMutex pointer is misaligned", file ..\..\include/QtCore/../../../../../../ndk_buildrepos/qt-desktop/src/corelib/thread/qmutex.h, line 100
Invalid parameter passed to C runtime function.
Invalid parameter passed to C runtime function.

请帮帮我

编辑:

fileuploader.cpp

#include "fileuploader.h"

FileUploader::FileUploader(QList<FileInfoWrapper> &fileList, const int start, const int offset, QObject *parent)
    : QObject(parent), start_(start), offset_(offset), iterator_(start - 1), fileList_(fileList) {
}

void FileUploader::init() {
    restFileUploader = new RestFileUploader();

    connect(restFileUploader, SIGNAL(uploadProgress(qint64)), this, SLOT(setUploadProgress(qint64)));
    connect(restFileUploader, SIGNAL(requestFinished(QNetworkReply*)), this, SLOT(handleRequestFinished(QNetworkReply*)));
    connect(restFileUploader, SIGNAL(sslErrors(QNetworkReply*,QList<QSslError>)), this, SLOT(handleSslErros(QNetworkReply*,QList<QSslError>)));
    connect(restFileUploader, SIGNAL(networkError(QNetworkReply::NetworkError)), this, SLOT(handleNetworkError(QNetworkReply::NetworkError)));

    containerName = "temp"

    qDebug() << "thread" << this->thread()->currentThreadId() << start_ << ":" << offset_;

    uploadNext();
}

void FileUploader::uploadNext() {
     qDebug() << "uploadNext" << this->thread()->currentThreadId();

    if((iterator_ + 1) < (start_ + offset_)) {
        iterator_++;

        restFileUploader->putBlob(containerName, fileList_.at(iterator_).fileName(), fileList_.at(iterator_).fileInfo().filePath());

    } else emit finished();
}

void FileUploader::setUploadProgress(qint64 tranfered) {

    fileList_[iterator_].setProgress(tranfered);

    emit progressChangedAt(iterator_);
}

void FileUploader::handleRequestFinished(QNetworkReply* reply) {

    qDebug() << "finished blob: " << iterator_ << " in thread " << this->thread()->currentThreadId();

    if(reply->error() > QNetworkReply::NoError) {
        qDebug() << reply->errorString();

        fileList_[iterator_].uploadFailed();

        emit progressChangedAt(iterator_);

    } else fileList_[iterator_].uploadFinished();

    emit statusChangedAt(iterator_);

    uploadNext();
}

void FileUploader::handleNetworkError(QNetworkReply::NetworkError error) {

    if(error > QNetworkReply::NoError) {
        fileList_[iterator_].uploadFailed();

        restFileUploader->cancelCurrentRequest();

        emit progressChangedAt(iterator_);
        emit statusChangedAt(iterator_);
    }
}

void FileUploader::handleSslErros(QNetworkReply *reply, const QList<QSslError> &errors) {

    if(reply->error() > QNetworkReply::NoError) {

        qDebug() << reply->errorString();

        fileList_[iterator_].uploadFailed();

        restFileUploader->cancelCurrentRequest();

        emit progressChangedAt(iterator_);
        emit statusChangedAt(iterator_);
    }
}

#include "restfileuploader.h"

void RestFileUploader::putBlob(const QString& container, const QString& blob, const QString& filePath) {
    QFile *uploadFile = new QFile(filePath, this); // <--- this maybe?
    uploadFile->open(QIODevice::ReadOnly); 

    QNetworkRequest request = this->createRestRequest("PUT", QString("%1/%2").arg(container, blob), uploadFile->size(), headers);

    reply_ = accessManager_->put(request, uploadFile);

    connect(reply_, SIGNAL(uploadProgress(qint64, qint64)), this, SLOT(reportUploadProgress(qint64, qint64)));
    connect(reply_, SIGNAL(error(QNetworkReply::NetworkError)), this, SLOT(reportNetworkError(QNetworkReply::NetworkError)));

    qDebug() << this->thread()->currentThreadId();
}

void RestFileUploader::cancelCurrentRequest() {
    reply_->abort();
}

RestFileUploader::~RestFileUploader() {
    qDebug() << "RestFileUploader deleted";

    reply_->deleteLater();
}

所以...... 1个线程有一件事要上传==好的。两个线程上的2个对象也是okey。当我尝试在两个线程上上传3个或更多对象时,它们都会变成地狱。

此外,它可能与UI在更改文件的同时读取文件的信息有关吗?

编辑:出于某种原因,当我在visual studio中编译它时,我的应用程序现在可以在4.8.0中运行。它可能与版本4.7.4有关吗?

3 个答案:

答案 0 :(得分:3)

QThread::start()实际上是thread的开头(作为不同的thread)。 QThread::run()只是一个常规函数,所以如果你先调用它而不先调用start(),那么你就是在主线程中执行它。

有趣的是,你的派生类是在主线程中创建的,所以它在主线程中“属于”。我猜你要把你的班级作为其他人的父母;这是在您调用start()后尝试执行此操作时生成错误消息的原因。你可以将这些对象保留为无父对象吗?

你将无法在另一个线程中创建gui对象,Qt只是不允许它(还是?)。但是可以创建其他对象,你不能在不同的线程中为它们提供父级。

答案 1 :(得分:2)

您收到的错误

ASSERT failure in QMutexLocker: "QMutex pointer is misaligned"
如果传递给构造函数的QMutex对象未在RAM中的2字节边界上对齐(至少在Qt 4.7.1中),则在创建QMutexLocker对象时会发生

QMutexLocker对象使用一个成员变量来表示内存中互斥锁的位置及其状态(是否锁定)。状态由变量的最低有效位表示,而互斥锁指针的最低有效位假定为零。如果该位不为零,则抛出上面的ASSERT异常。

我能想到的QMutex指针未对齐的唯一原因是内存泄漏或损坏。检查是否销毁你分配的所有内存(特别是在循环中)并检查所有类型转换(你可能已经将较小类型的指针转​​换为更大类型的指针,损坏内存)和以null结尾的字符串(这会损坏内存)如果没有正确终止)。最后,验证您在线程之间共享的所有内存的线程安全性。

答案 2 :(得分:1)

这可能是因为创建了应用程序中某个对象的顺序。 我建议继承QObject而不是QThread,并将对象移动到工作线程(QObject :: moveToThread())。还要将FileUploader中初始化的任何代码移动到FileUploader中的单独插槽,例如init()。在线程运行时调用init(QMetaObject :: invokeMethod())(在工作线程上调用start之后)。 E.g:

FileUploader : public QOject
{
...
public slots:
void init() { Foo *foo = new Foo(this); }
}

// main thread
QThread worker;
FileUploader *fup = new FileUploader();
fup->moveToThread(&worker);
worker.start();
QMetaObject::invokeMethod(fup, "init", Qt::QueuedConnection); 
//