QtConcurrent::run and QList<QListWidgetItem*>::Iterator crashes
-
I'm on a small app, which fills a
QListWidget
with newedQListWidgetItem
s (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
QList
pointers 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 theQListWidgetItem
s 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
QtConcurrent
is 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
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 theQList
in another class and/or maybe theQListWidget
model? -
@Max13
Do whatever is you want to do with GUI in the main thread and callQCoreApplication::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, theCrawler
object now crawls usingQt::Concurrent
and 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