Есть довольно жирный список, обрабатываемый на C++. В каждом элементе списка 17 строк QString, 3 картинки QPicture (правда небольших), 2 вещественных числа, 1 целое и два логических. Вся эта лабуда живёт в собственном классе, из указателей на объекты которого состоит собственно QList. В одном объекте этот список хранится и обрабатывается, другим объектом отображается при помощи QML. Список в процессе модифицируется, тогда объект хранитель передаёт объекту отображателю ссылку через сигнал-слот. Объект отображатель передёргивает контекст, и изображение списка соответствует его данным. Всё хорошо работает, пока я не начинаю удалять элементы из списка. Точнее даже - если я удаляю один элемент, то всё хорошо работает. Но если я в цикле последовательно удаляю несколько элементов подряд, разумеется через удаление одного, то всё падает. В соседней теме я это постил, но её закончил, поэтому повторю тут. Объект обработчик удаляет помеченные элементы из списка, и посылает сигнал:
void ProcessSheet::deleteSeveral()
{
for( int i = 0; i < collection.size(); )
{
if( collection.at( i )->todelete() )
delete collection.takeAt( i );
else
i++ ;
}
emit sendCollection( (QList<QObject*>&) collection );
}
Объект отображатель получает сигнал:
void DrawSheet::receiveCollection(QList<QObject*>& sheet)
{
rootContext()->setContextProperty("CollectionList", QVariant::fromValue(sheet));
setSource(QUrl( qmlfile ));
}
Всё прекрасно работает, пока N == 1. При большем числе падает глубоко внутри setContextProperty(). Падает 100% в одном и том же месте и на ПК Linux, и на смартфоне Android.
При рассмотрении стека после падения, я предположил, что возникает гонка за памятью - очевидно setContextProperty() внутри выполняется в отдельном треде, и возможно этот тред обгоняет незавершённое освобождение памяти после удаления сложного объекта, что приводит к обращению по неверному указателю.
Соединение sendCollection( QList<QObject*>& ) и receiveCollection( QList<QObject*>& ) производится в QtDesigner, то есть выполняется Qt::DirectConnection. Я удалил его, и попытался в коде соединить эти сигнал и слот как Qt::QueuedConnection, чтобы вызов отображения оказался в очереди, и выполнился когда все удаления будут завершены (по опыту это часто работает). К моему большому удивлению этот connect() не выполнился. Он вернул
false. Если я заменил тип на Qt::DirectConnection - соединение выполняется, получаю
true, но так программа падает. Подтверждение гонки тредов я получил когда соединил сигнал и слот через Qt::BlockingQueuedConnection - внутри setContextProperty() всё повисло с выдачей в консоль сообщения о dead lock.
В Интернет ничего похожего не нашёл. Кто-нибудь что-нибудь читал про выполнение setContextProperty()? Может какой-нибудь недокументированный семафор есть, чтобы задержать его? Или другой способ гарантировать завершение удаления? Пробовал сразу после него QApplication::processEvents();, пробовал это же перед выполнением setContextProperty() - не помогло.