我试图创建一个将创建新线程的上传器,并且在每个线程中我都有一个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)并对其进行请求),因此在构造函数中未创建任何内容(这将导致它最终出现在主线程中?)。运行函数创建一个要提供给QNetworkAccessManager的请求,然后不执行任何操作,直到发出“finished(QNetworkReply)”信号,然后我抓取下一个请求(依此类推,直到完成列表)。
然后,我在主应用程序中创建了两个新线程,当我使用run()启动它们时,它的工作原理是,除了两个线程上的ID相同之外。如果我改为调用“start()”,则会崩溃:
QObject:无法为处于不同线程中的父级创建子级。
( parent 是FileUploader(0x2580748), parent 的线程是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);
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个线程上载一件事== ok。两个线程上的2个对象也很不错。当我尝试在两个线程上载3个或更多对象时,一切都会陷入困境。
另外,它与UI在我更改文件的同时读取文件的信息有关吗?
编辑:出于某种原因,当我在Visual Studio中进行编译时,我的应用程序现在可以在4.8.0中工作。可能与4.7.4版有关吗?
最佳答案
QThread::start()
实际上是thread
的起始位置(作为另一个thread
)。 QThread::run()
只是一个常规函数,因此如果您不先调用start()
而调用它,那么您将在主线程中执行它。
有趣的是,您的派生类是在主线程中创建的,因此它“属于”主线程。我猜你是要把你作为 parent 的类(class)带给其他人。这是您在调用start()
之后尝试执行此操作时生成错误消息的原因。您可以让那些对象没有 parent 吗?
您将无法在另一个线程中创建gui对象,Qt只是不允许这样做(还好吗?)。但是可以创建其他对象,只是不能在其他线程中为它们提供父对象。