Russian Qt Forum

Qt => Установка, сборка, отладка, тестирование => Тема начата: cydeamon от Май 16, 2015, 10:58



Название: Странный баг с qDebug
Отправлено: 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.


Название: Re: Странный баг с qDebug
Отправлено: Bepec от Май 16, 2015, 11:14

На первый взгляд у вас возникает ситуация, когда currentCategoryUpdate создаётся, стартует, цикл создаёт новый currentCategory и тут вызывается слот downloadFinished и удаляет его ещё до всяких соединений. И дальше уже ситуация идёт вразнос :D


Название: Re: Странный баг с qDebug
Отправлено: cydeamon от Май 16, 2015, 11:24
Не. С кодом всё в порядке. Суть в том что из-за qDebug'а всё останавливается после первого обновления (точнее, из-за отсутствия).
Всё останавливается если убрать тот самый qDebug, который вообще ни на что не должен влиять.
Всё нормально если его оставить. Он выводит только строку, никаких вычислений не делает, он по определению не может ничего поломать.
В этом странность )


Название: Re: Странный баг с qDebug
Отправлено: cydeamon от Май 16, 2015, 11:28

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


Название: Re: Странный баг с qDebug
Отправлено: Igors от Май 16, 2015, 12:26
Не. С кодом всё в порядке.
Не видно синхронизации. Напр пока categoriesUpdateQuery->length() возвращает ноль - так и будет молотить? Или то какой-то хитрый length с мутексом?

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

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


Название: Re: Странный баг с qDebug
Отправлено: cydeamon от Май 16, 2015, 12:58
Не. С кодом всё в порядке.
Не видно синхронизации. Напр пока categoriesUpdateQuery->length() возвращает ноль - так и будет молотить? Или то какой-то хитрый length с мутексом?

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

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

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

Но цикл же постоянный, даже если в первый раз он вернул неправильный результат, при следующем проходе он может вернуть правильный. Не вижу проблемы.


Название: Re: Странный баг с qDebug
Отправлено: Igors от Май 16, 2015, 13:52
Код:
   ...
   Q_ASSERT(updatng == true);    // добавьте эту строку
    categoriesUpdateQuery->removeFirst();
    delete currentCategoryUpdate;
    updating = false;
}