QtConcurrent::run and QList<QListWidgetItem*>::Iterator crashes



  • I'm on a small app, which fills a QListWidget with newed QListWidgetItems (around 40'000 items) while some of them are stored in a QList<QListWidgetItem*> (almost all of them). All are part of the same class: MainWidget.

    From there, I assumed that the QList pointers are exactely the same as some of the QListWidget's model. Stop me if I'm wrong.

    So based on that, when I click a button, a slot is executed (using QtConcurrent) to toggle the hidden attribute of all the QListWidgetItems contained in the QList<QListWidgetItem*>. Here is the code for toggle:

    void    MainWidget::toggle(void)
    {
        bool    newBool(!(*(this->m_okItems.cbegin() + 1))->isHidden());
    
        for (QList<QListWidgetItem*>::Iterator i(this->m_okItems.begin()); i != this->m_okItems.end(); ++i) {
            (*i)->setHidden(newBool);
        }
    
        this->endLoading();
    }
    

    And here is how I start the it

    QtConcurrent::run(this, &MainWidget::toggle);
    

    The first time I start this, it's OK. All the "hidden" items are shown, and vice-versa. The second time, it crashes during the execution of the QtConcurrent, and the debugger points to the asm instructions (I don't know ASM). I've also tried to put a qDebug() with a counter to see at which point it fails, if it's at the same item or not. It crashes randomly. Sometimes at the 35'000 th iteration, sometimes at 16'000th (rounded).

    I can't see how it could be related to thread safety as I disable the main GUI while the QtConcurrent is running (endLoading() is made to reenable to GUI). What am I missing?

    Thanks for your help.


  • Qt Champions 2017

    @Max13

    So based on that, when I click a button, a slot is executed (using QtConcurrent) to toggle the hidden attribute of all the QListWidgetItems contained in the QList<QListWidgetItem*>.

    This isn't allowed, so results are undefined (and undocumented).

    I can't see how it could be related to thread safety as I disable the main GUI while the QtConcurrent is running (endLoading() is made to reenable to GUI). What am I missing?

    You're missing the fact that QWidget and its descendants aren't reentrant.

    Kind regards.



  • @kshegunov Thanks for the hint. That's also why using a QMutex didn't change anything. So, please tell me how can I perform the heavy tasks in background on the list? Do I need to set the QList in another class and/or maybe the QListWidget model?


  • Qt Champions 2017

    @Max13
    Do whatever is you want to do with GUI in the main thread and call QCoreApplication::processEvents manually so you don't freeze up the user interface. Something like this:

    void MainWidget::toggle()
    {
        bool newBool = !m_okItems.at(1)->isHidden(); //< Just use C++, all the pointer dereferencing is making my head spin
    
        typedef QList<QListWidgetItem *>::ConstIterator ListIterator;
        for (ListIterator i = m_okItems.constBegin(); i != m_okItems.constEnd(); ++i)  {
            (*i)->setHidden(newBool);
            QCoreApplication::processEvents();
        }
    
        endLoading();
    }
    


  • @kshegunov Too bad :( I was afraid that was the only possible way... I tried that but it slowed down my app (maybe because each time I'm refreshing the whole widget for 1 add).

    I think I can get around the visual issue by creating a "Loading" widget with a progress bar and all that things in a thread instead. Then, I won't have to care much about the main GUI freezing, isn't it?



  • @kshegunov said:

    You're missing the fact that QWidget and its descendants aren't reentrant.

    Actually, I missed more than that... I completely miss the fact that, when dealing with QWidget or simillar + threads, that exactely when I should have used signal/slot mechanism... I feel dumb about it, but anyway, the Crawler object now crawls using Qt::Concurrent and send a signal with the text to add to the QListWidget, and then a MainWidget's slot is called to create and add the item.

    Thanks for your help