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.
The error you are receiving
ASSERT failure in QMutexLocker: "QMutex pointer is misaligned"
occurs on creation of a QMutexLocker object if the QMutex object passed to the constructor is not aligned on a 2-byte boundary in RAM (in Qt 4.7.1 at least).
The QMutexLocker object uses one member variable to represent both the location of the mutex in memory and its state (whether it is locked or not). The state is represented by the least significant bit of the variable, while the least significant bit of the mutex pointer is assumed to be zero. If this bit is not zero, the ASSERT exception above is thrown.
The only reason for misalignment of the QMutex pointer I can think of is a memory leak or corruption. Check whether you destroy all memory that you allocate (especially in loops) and check all typecasts (you might have casted a pointer of a smaller type to a pointer of a bigger type, damaging memory) and null-terminated strings (which will damage memory if not properly terminated). Finally, verify the thread safety of all memory that you share across threads.
This is probably because the order some object in your application is created. I would recommend inherit from QObject instead of QThread, and move the object to a worker thread instead (QObject::moveToThread()). Also move any code that is initialized in FileUploader to a separate slot in FileUploader, say init(). Invoke init (QMetaObject::invokeMethod()) when the thread is running (after calling start on the worker thread). 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);
//
来源:https://stackoverflow.com/questions/9458664/qthread-assert-failure-in-qmutexlocker-qmutex-pointer-is-misaligned