QMutexLocker 中的 QThread ASSERT 失败:“QMutex 指针未对齐", [英] QThread ASSERT failure in QMutexLocker: "QMutex pointer is misaligned",

查看:217
本文介绍了QMutexLocker 中的 QThread ASSERT 失败:“QMutex 指针未对齐",的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试创建一个上传器来创建新线程,并且在每个线程中我都有一个 QNetworkAccessManager.所有上传线程都有一个对共享列表的引用,并将使用开始和结束索引拆分它.

上传器看起来像这样:

 class FileUploader : public QObject {Q_OBJECT上市:显式 FileUploader(QList<FileInfoWrapper> &fileList, const int start = 0, const int offset = 0, QObject *parent = 0);无效uploadNext();QString 容器名称;私人的:int start_, offset_, iterator_;QList&fileList_;RestFileUploader *restFileUploader;信号:void progressChangedAt(int row);void statusChangedAt(int row);无效完成();公共插槽:无效初始化();私人插槽:void setUploadProgress(qint64 传输);void handleRequestFinished(QNetworkReply* reply);void handleSslErros(QNetworkReply *reply, const QList &errors);void handleNetworkError(QNetworkReply::NetworkError error);};

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

然后我在主应用程序中创建两个新线程,当我使用 run() 启动它们时,它可以工作,只是两个线程上的 ID 相同.如果我改为调用start()",它会崩溃:QObject:无法为不同线程中的父级创建子级.(父为FileUploader(0x2580748),父线程为QThread(0x4fb2b8),当前线程为FileUploader(0x2580748)

但是!就在我开始逐步执​​行列表之前,我打印了 threadId 并且它们不再相同.

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

我对其进行了更改并将其重命名为 run 以启动并制作此包装器(并且我不再使用this"调用 NetworkAccessManager 或 RestFileUploader):

FileUploader *fileUploader = new FileUploader(fileList_, start, (offset == 0 ? (fileList_.count() - start) : offset));QThread *fileUploaderThread = new QThread;fileUploader->moveToThread(fileUploaderThread);连接(fileUploader,信号(progressChangedAt(int)),model_,SLOT(reportProgressChanged(int)));连接(fileUploader,信号(statusChangedAt(int)),model_,SLOT(reportStatusChanged(int)));fileUploaderThread->start();QMetaObject::invokeMethod(fileUploader, "init", Qt::QueuedConnection);

当上传一个对象有效时,因为我当时只使用一个线程.但是当我拆分更多对象时,应用程序崩溃并显示以下错误消息:

ASSERT 在 QMutexLocker 中失败:QMutex 指针未对齐",文件 ..\..\include/QtCore/../../../../../../ndk_buildrepos/qt-desktop/src/corelib/thread/qmutex.h,第 100 行传递给 C 运行时函数的参数无效.传递给 C 运行时函数的参数无效.

请帮帮我

fileuploader.cpp

#include "fileuploader.h"FileUploader::FileUploader(QList &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();连接(restFileUploader,信号(uploadProgress(qint64)),这个,SLOT(setUploadProgress(qint64)));连接(restFileUploader, SIGNAL(requestFinished(QNetworkReply*)), this, SLOT(handleRequestFinished(QNetworkReply*)));连接(restFileUploader,信号(sslErrors(QNetworkReply*,QList)),这个,SLOT(handleSslErros(QNetworkReply*,QList)));连接(restFileUploader,信号(网络错误(QNetworkReply::NetworkError)),这个,SLOT(handleNetworkError(QNetworkReply::NetworkError)));容器名称 = "临时"qDebug() <<线程"<<this->thread()->currentThreadId()<<开始_<<:"<<抵消_;上传下一个();}void FileUploader::uploadNext() {qDebug() <<上传下一个"<<this->thread()->currentThreadId();if((iterator_ + 1) < (start_ + offset_)) {迭代器_++;restFileUploader->putBlob(containerName, fileList_.at(iterator_).fileName(), fileList_.at(iterator_).fileInfo().filePath());否则发出完成();}void FileUploader::setUploadProgress(qint64 传输) {fileList_[iterator_].setProgress(transfered);发出 progressChangedAt(iterator_);}void FileUploader::handleRequestFinished(QNetworkReply* reply) {qDebug() <<完成的斑点:" <<迭代器_<<在线程中" <<this->thread()->currentThreadId();if(reply->error()>QNetworkReply::NoError) {qDebug() <<回复->errorString();fileList_[迭代器_].uploadFailed();发出 progressChangedAt(iterator_);} else fileList_[iterator_].uploadFinished();发出 statusChangedAt(iterator_);上传下一个();}void FileUploader::handleNetworkError(QNetworkReply::NetworkError error) {if(error > QNetworkReply::NoError) {fileList_[迭代器_].uploadFailed();restFileUploader->cancelCurrentRequest();发出 progressChangedAt(iterator_);发出 statusChangedAt(iterator_);}}void FileUploader::handleSslErros(QNetworkReply *reply, const QList &errors) {if(reply->error()>QNetworkReply::NoError) {qDebug() <<回复->errorString();fileList_[迭代器_].uploadFailed();restFileUploader->cancelCurrentRequest();发出 progressChangedAt(iterator_);发出 statusChangedAt(iterator_);}}#include "restfileuploader.h"void RestFileUploader::putBlob(const QString& container, const QString& blob, const QString& filePath) {QFile *uploadFile = new QFile(filePath, this);//<--- 这可能吗?上传文件->打开(QIODevice::ReadOnly);QNetworkRequest request = this->createRestRequest("PUT", QString("%1/%2").arg(container, blob), uploadFile->size(), headers);回复_=访问管理器_->放置(请求,上传文件);连接(回复_,信号(uploadProgress(qint64,qint64)),这个,SLOT(reportUploadProgress(qint64,qint64)));连接(回复_,信号(错误(QNetworkReply::NetworkError)),这个,SLOT(reportNetworkError(QNetworkReply::NetworkError)));qDebug() <<this->thread()->currentThreadId();}void RestFileUploader::cancelCurrentRequest() {回复_->中止();}RestFileUploader::~RestFileUploader() {qDebug() <<"RestFileUploader 已删除";回复_->deleteLater();}

所以... 1 个线程上传一件事 == 好的.两个线程上的 2 个对象也很好.当我尝试在两个线程上上传 3 个或更多对象时,一切都变得糟糕透了.

另外,这是否与 UI 在我更改文件信息的同时读取文件信息有关?

出于某种原因,当我在 Visual Studio 中编译它时,我的应用程序现在可以在 4.8.0 中运行.会不会跟4.7.4版本有关系?

解决方案

QThread::start() 是实际启动线程(作为不同的线程).QThread::run() 只是一个普通的函数,所以如果你在没有先调用 start() 的情况下调用它,你就是在主线程中执行它.>

有趣的是,您的派生类是在主线程中创建的,因此它属于"主线程.我猜你是在把你的班级作为家长交给别的东西;当您在调用 start() 后尝试执行此操作时,这就是生成错误消息的原因.你可以让这些对象没有父级吗?

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

Im trying to create an uploader that will create new threads and in every thread I have a QNetworkAccessManager. All the uploader threads have a reference to a shared list and will split it by using start and end indexes.

The Uploader looks something like this:

 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);

};

Then, in the run() function I create the new RestFileUploader(this)(Pretty much a object which creates its own new QNetworkAccessManager(this) and put requests on it) so that nothing is created in the constructor(which would cause it to end up in the main thread instead?). The run function creates a request to be given to the QNetworkAccessManager and then does nothing until that signals "finished(QNetworkReply)" and then I grab the next one (and so on until the list is stepped through).

Then I create two new threads in the main application and when I start them using run() it works except that the ID is the same on both the threads. If I instead call "start()" it crashes with: QObject: Cannot create children for a parent that is in a different thread. (Parent is FileUploader(0x2580748), parent's thread is QThread(0x4fb2b8), current thread is FileUploader(0x2580748)

BUT! Just before I start step through the list, I print the threadId and they are no longer the same.

What am I doing wrong or should I just do this: http://labs.qt.nokia.com/2006/12/04/threading-without-the-headache/ ?

Edit:

I changed it and renamed run to start and made this wrapper(and I no longer call NetworkAccessManager or RestFileUploader with "this"):

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);

When uploading one object works, since I only use one thread then. But when I have more objects that I split up, the application crashed brutally with this error message:

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.

Please help me

Edit:

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();
}

So... 1 thread with one thing to upload == ok. 2 objects on two threads are also okey. When I try to upload 3 or more objects on the two threads it all goes to hell.

Also, could it have something to do with that the UI is reading the info of the files at the same time as I change it?

EDIT: For some reason my app now works in 4.8.0 when I compile it in visual studio. Could it have something to do with version 4.7.4?

解决方案

QThread::start() is what actually starts the thread (as a different thread). QThread::run() is just a regular function, so if you call it without calling start() first, you're executing it in the main thread.

The funny thing about it is that your derived class was created in the main thread, so it "belongs" in the main thread. I'm guessing you're giving your class as the parent to something else; this is what is generating the error message when you try to do this after calling start(). Can you leave those objects parent-less?

You won't be able to create gui objects in another thread, Qt just doesn't allow it (yet?). But other objects can be created, you just can't give them a parent in a different thread.

这篇关于QMutexLocker 中的 QThread ASSERT 失败:“QMutex 指针未对齐",的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆