QtConcurrent::run and QList<QListWidgetItem*>::Iterator crashes
-
I'm on a small app, which fills a
QListWidgetwith newedQListWidgetItems (around 40'000 items) while some of them are stored in aQList<QListWidgetItem*>(almost all of them). All are part of the same class:MainWidget.From there, I assumed that the
QListpointers are exactely the same as some of theQListWidget'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 theQListWidgetItems contained in theQList<QListWidgetItem*>. Here is the code fortoggle: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 aqDebug()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
QtConcurrentis running (endLoading()is made to reenable to GUI). What am I missing?Thanks for your help.
-
I'm on a small app, which fills a
QListWidgetwith newedQListWidgetItems (around 40'000 items) while some of them are stored in aQList<QListWidgetItem*>(almost all of them). All are part of the same class:MainWidget.From there, I assumed that the
QListpointers are exactely the same as some of theQListWidget'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 theQListWidgetItems contained in theQList<QListWidgetItem*>. Here is the code fortoggle: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 aqDebug()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
QtConcurrentis running (endLoading()is made to reenable to GUI). What am I missing?Thanks for your help.
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
QWidgetand its descendants aren't reentrant.Kind regards.
-
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
QWidgetand its descendants aren't reentrant.Kind regards.
@kshegunov Thanks for the hint. That's also why using a
QMutexdidn't change anything. So, please tell me how can I perform the heavy tasks in background on the list? Do I need to set theQListin another class and/or maybe theQListWidgetmodel? -
@kshegunov Thanks for the hint. That's also why using a
QMutexdidn't change anything. So, please tell me how can I perform the heavy tasks in background on the list? Do I need to set theQListin another class and/or maybe theQListWidgetmodel?@Max13
Do whatever is you want to do with GUI in the main thread and callQCoreApplication::processEventsmanually 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(); } -
@Max13
Do whatever is you want to do with GUI in the main thread and callQCoreApplication::processEventsmanually 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?
-
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
QWidgetand its descendants aren't reentrant.Kind regards.
@kshegunov said:
You're missing the fact that
QWidgetand its descendants aren't reentrant.Actually, I missed more than that... I completely miss the fact that, when dealing with
QWidgetor simillar + threads, that exactely when I should have used signal/slot mechanism... I feel dumb about it, but anyway, theCrawlerobject now crawls usingQt::Concurrentand send a signal with the text to add to theQListWidget, and then aMainWidget's slot is called to create and add the item.Thanks for your help