Russian Qt Forum
Май 03, 2024, 22:43 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: Странный баг с qDebug  (Прочитано 3915 раз)
cydeamon
Гость
« : Май 16, 2015, 10:58 »

Пишу программу которая скачивает с сайта информацию о поступлении новых изображений с разделением по категориям. Есть тред который постоянно выполняется и проверяет обновления.
Из основного потока ему передается указатель на очередь обновления. После обновления первой в векторе категории, она удяляется из очереди и начинается обновление следующей.
Код:
void UpdateManager::run()
{
    qDebug() << "UpdateManager запущен";

    while(true)
    {
        if( categoriesUpdateQuery->length())  // Если очередь обновлений не пуста
        {
            if( !updating ) // Если обновление уже не запущено
            {
                qDebug() << "Начинаю обновление категории " << categoriesUpdateQuery->first()->getCategoryName();
                currentCategoryUpdate = new ImagesDataDownloader( categoriesUpdateQuery->first(),
                                                                  allImages, settings);

               // ImageDataDownloader - Еще один тред, который, собственно, и выполняет обновление, UpdateManager только их запускает и организует их запуск по одной за раз.

                connect(currentCategoryUpdate, SIGNAL(updateStatusBar(QString)), SIGNAL(updateStatusBar(QString)));
                connect(currentCategoryUpdate, SIGNAL(downloadFinished()), categoriesUpdateQuery->first(), SLOT(update_availableImagesNum())); // Обновление QLabel показывающего количество изображений в категории
                connect(currentCategoryUpdate, SIGNAL(downloadFinished()), SLOT(onCategoryUpdated()));

                currentCategoryUpdate->start();

                updating = true;
            }
        }
        qDebug() << "UpdateManager работает";
    }
}


void UpdateManager::onCategoryUpdated()
{
    qDebug() << "Завершено обновление категории " << categoriesUpdateQuery->first()->getCategoryName();

    emit categoryUpdated( categoriesUpdateQuery->first());

    categoriesUpdateQuery->removeFirst();

    delete currentCategoryUpdate;

    updating = false;
}

Беда в чем: Если убрать qDebug() << "UpdateManager работает";  (который вечно гадит в вывод и мешает отладке), то обновление останавливается после первой в очереди категории и дальше не идет. Если qDebug оставить, то всё проходит кооректно, все категории обновляются по очереди.
Как такое возможно?
Qt 5.4. Linux.
« Последнее редактирование: Май 16, 2015, 11:04 от Cydeamon » Записан
Bepec
Гость
« Ответ #1 : Май 16, 2015, 11:14 »


На первый взгляд у вас возникает ситуация, когда currentCategoryUpdate создаётся, стартует, цикл создаёт новый currentCategory и тут вызывается слот downloadFinished и удаляет его ещё до всяких соединений. И дальше уже ситуация идёт вразнос Веселый
Записан
cydeamon
Гость
« Ответ #2 : Май 16, 2015, 11:24 »

Не. С кодом всё в порядке. Суть в том что из-за qDebug'а всё останавливается после первого обновления (точнее, из-за отсутствия).
Всё останавливается если убрать тот самый qDebug, который вообще ни на что не должен влиять.
Всё нормально если его оставить. Он выводит только строку, никаких вычислений не делает, он по определению не может ничего поломать.
В этом странность )
« Последнее редактирование: Май 16, 2015, 11:30 от Cydeamon » Записан
cydeamon
Гость
« Ответ #3 : Май 16, 2015, 11:28 »


На первый взгляд у вас возникает ситуация, когда currentCategoryUpdate создаётся, стартует, цикл создаёт новый currentCategory и тут вызывается слот downloadFinished и удаляет его ещё до всяких соединений. И дальше уже ситуация идёт вразнос Веселый
Если он удаляется, стартует следующий. Удаляется один элемент, а не все. Ошибок сегментирования и т.п. нет.
Такое ощущение что UpdateManager просто сдыхает, но в вывод ничего об этом не пишет. Может Qt подумал что он ничем не занят и задушил туниядца? А qDebug его разубедил?
Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #4 : Май 16, 2015, 12:26 »

Не. С кодом всё в порядке.
Не видно синхронизации. Напр пока categoriesUpdateQuery->length() возвращает ноль - так и будет молотить? Или то какой-то хитрый length с мутексом?

UpdateManager::run() и UpdateManager::onCategoryUpdated() выполняются в разных нитках? Если да, то как гарантируется корректное выполнение length() во время removeFirst?

С печатью работает, без нее нет (или наоборот) - случай нередкий. Меняется нагрузка на нитку, вот баги и вылазят (или наоборот)
Записан
cydeamon
Гость
« Ответ #5 : Май 16, 2015, 12:58 »

Не. С кодом всё в порядке.
Не видно синхронизации. Напр пока categoriesUpdateQuery->length() возвращает ноль - так и будет молотить? Или то какой-то хитрый length с мутексом?

UpdateManager::run() и UpdateManager::onCategoryUpdated() выполняются в разных нитках? Если да, то как гарантируется корректное выполнение length() во время removeFirst?

С печатью работает, без нее нет (или наоборот) - случай нередкий. Меняется нагрузка на нитку, вот баги и вылазят (или наоборот)

Неизвестно когда пользователь запустит обновление, потому цикл постоянный. Пользователь нажимает на "Обновить" напротив интересующей категории, она добавляется в очередь обновлений.  categoriesUpdateQuery->length() уже не ноль, начинается обновление.
Гарантия того, что не запустится другое обновления - bool updating, который принимает true если обновление уже идет. И не зависимо от того что вернет length(), следующее обновление не запустится, поскольку updating==true;
UpdateManager реагирует на сигнал downloadFinished() и запускает onCategoryUpdated(), так что запускает их один тред.

Но цикл же постоянный, даже если в первый раз он вернул неправильный результат, при следующем проходе он может вернуть правильный. Не вижу проблемы.
« Последнее редактирование: Май 16, 2015, 13:05 от Cydeamon » Записан
Igors
Джедай : наставник для всех
*******
Offline Offline

Сообщений: 11445


Просмотр профиля
« Ответ #6 : Май 16, 2015, 13:52 »

Код:
   ...
   Q_ASSERT(updatng == true);    // добавьте эту строку
    categoriesUpdateQuery->removeFirst();
    delete currentCategoryUpdate;
    updating = false;
}
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.055 секунд. Запросов: 23.