Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

Strange errors from QThread



  • I have a QThread that downloads icons via cURL from a wikia, and for some reason whenever i execute the download, or skip it if the file already exists my program crashes with a weird error, theres quite a few lines of code that arent really neccessary for this error so i've tried to narrow it down to just the pertinent parts

    The Thread creator

    while (q.next()) {
                   ...
    		if (!fileExists(istemp->iconPath)) {
    			QThread *itemRetriever = new QThread;
    			threadsRemaining++;
    			ItemSearchIconWorker *icw = new ItemSearchIconWorker(istemp, &threadsRemaining);
    			icw->itemWidget = istemp;
    			QObject::connect(itemRetriever, SIGNAL(started()), icw, SLOT(process()));
    			QObject::connect(icw, SIGNAL(finished()), itemRetriever, SLOT(quit()));
    			QObject::connect(icw, SIGNAL(finished()), icw, SLOT(deleteLater()));
    			QObject::connect(itemRetriever, SIGNAL(finished()), itemRetriever, SLOT(deleteLater()));
    			icw->moveToThread(itemRetriever);
    			threads.insert(threads.end(), itemRetriever);
    			connect(icw, SIGNAL(iconDLComplete()), this, SLOT(threadComplete()));
    			totalThreads++;
    		}
    		else {
    			QIcon *newIcon = new QIcon;
    			newIcon->addFile(istemp->iconPath, QSize(28, 28));
    			istemp->itemIconLabel->setPixmap(newIcon->pixmap(newIcon->actualSize(QSize(28, 28))));
    		}
    		index++;
    		
    	}
    	for (QThread *t : threads) {
    		t->start();
    	}
    

    The Worker's proccess()

    	ItemSearchItem *temp = dynamic_cast<ItemSearchItem*>(istemp);
    
    
    	//downloadFileS("abcd", "abcd");
            // This usually downloads the requested image, but is commented out for testing (still breaks even without it)
    
    	QIcon *tempIcon = new QIcon;
    	tempIcon->addFile(temp->iconPath, QSize(28,28));
    	temp->itemIconLabel->setPixmap(tempIcon->pixmap(tempIcon->actualSize(QSize(28, 28))));
    
    	emit iconDLComplete();
    
    	emit finished();
    

    The threadComplete slot just decreases threadsRemaining by 1, then emits lookupFinished() if its 0

    lookupFinished is connected to a slot that fills a list, but it never reaches it, as it just crashes right before

    The error i get when it crashes is

    ASSERT failure in QVector<T>::at: "index out of range", file c:\users\qt\work\qt\qtbase\include\qtcore\../../src/corelib/tools/qvector.h, line 424
    Debug Error!
    
    Program: ...x64\Debug\Qt5Cored.dll
    Module: 5.10.1
    File: c:\users\qt\work\qt\qtbase\include\qtcore\../../src/corelib/tools/qvector.h
    Line: 424
    
    ASSERT failure in QVector<T>::at: "index out of range", file c:\users\qt\work\qt\qtbase\include\qtcore\../../src/corelib/tools/qvector.h, line 424
    
    (Press Retry to debug the application)
    QWidget::repaint: Recursive repaint detected
    

    i also get this message

    QBackingStore::endPaint() called with active painter on backingstore paint device
    

    That message spams itself until i close the program, and if i trace it in debug the call stack just leads me to my programs .exec() in my main() function, and i'm not using any QVectors

    And this is the call stack from the error

    https://i.imgur.com/Ckb8SNn.png



  • from http://doc.qt.io/qt-5/thread-basics.html

    All widgets and several related classes, for example QPixmap, don't work in secondary threads.

    Never manipulate the UI (itemIconLabel->setPixmap) or QPixmaps (tempIcon->pixmap) from secondary threads


  • Qt Champions 2017

    In addition to @VRonin, you don't need the hundreds of threads. Either use a (thread-safe) queue for the jobs, or simply QtConcurrent::run to use the already existing thread pool. Threads are rather heavy on Linux, so it makes little sense to create them to fetch single item over the network and then destroy them for no obvious reason.



  • You can also use a single QNetworkAccessManager instead of cUrl to download the icons with no need to implement multithreading at all



  • @SolaVitae

    Along with what @VRonin was saying about accessing (updating) the UI from other than the main thread, you must be very careful using QVector, QList, QMap, std::vector, std::list, std::map, etc. across threads as they are intrinsically NOT multi-thread safe. Synchronizing mechanisms must be employed.

    Using thread pools is very effective for managing your threads and resources.



  • I feel like this is a perfect personification of the "came searching for copper but found gold meme", Sometime in the past I acknowledged that modifying UI elements in a secondary thread caused crashes, I even fixed it, then when I moved my project from computer to computer i must have copied an old file or something, and forgot that that was a no-no. But I digress, not only did this thread solve my problem, it also showed me a way to ditch cURL, and rely solely on QT, as well as circumvent the necessity of the threading in the first place, so thank you all for answering my question and more @Buckwheat / @VRonin /@kshegunov


Log in to reply