|
|||||||
Что делать, если сообщения в консоли Qt появляются с задержкой
Время создания: 09.10.2021 11:55
Автор: xintrea
Текстовые метки: c++, Qt, консоль, Qt Creator, отладка, лог, логирование, qDebug, qWarning, printf, вывод, печать, qInstallMessageHandler, handler, хендлер
Раздел: Компьютер - Программирование - Язык C++ (Си++) - Библиотека Qt - Принципы написания кода
Запись: xintrea/mytetra_syncro/master/base/1633769742lrsabnv54n/text.html на raw.github.com
|
|||||||
|
|||||||
Программисты, у которых в коде используются функции языка СИ printf() / fprintf(), замечают, что такой вывод в консоль появляется со значительной задержкой (до нескольких секунд) в окне "Вывод приложения" QtCreator-а. Если это же приложение запустить в любом терминале, от xterm до konsole, то такой проблемы не будет. Этот баг окна вывода QtCreator появлялся в 3-м и в 4-м креаторе, его исправляли, и снова ломали, в общем, в арсенале Qt-программиста должно быть решение, как эту проблему можно обойти. Примечание. Кому вообще в XXI веке может понадобиться использование функций printf() / fprintf() в коде на C++/Qt? Такая ситуация может возникнуть в случае, если заменяется стандартный хендлер отладочного вывода путем использования функции qInstallMessageHandler( ourDebugPrintFunction ) Проблема в том, что внутри ourDebugPrintFunction() нельзя использовать потоковый вывод через qDebug(), qWarning() и прочие подобные инструменты, так как получится рекурсия. Поэтому для вывода в консоль надо использовать либо стандартные C++ потоки ввода/вывода (что медленно), либо стандартные функции вывода библиотеки iostream. Ниже приведена простейшая реализация хендлера, в котором возникает проблема с задержкой появления сообщений в окне QtCreator: void LogHelper::ourDebugPrintFunction(QtMsgType type, const QMessageLogContext &context, const QString &msgText) { Q_UNUSED(context) switch (type) { case QtDebugMsg: // Отладочный вывод возможен только при компиляции в режиме отладки #ifdef QT_DEBUG smartPrintDebugMessage("[DBG] "+msgText+"\n"); #endif break; case QtWarningMsg: smartPrintDebugMessage("[WRN] "+msgText+"\n"); break; case QtCriticalMsg: smartPrintDebugMessage("[CRERR] "+msgText+"\n"); break; case QtFatalMsg: smartPrintDebugMessage("[FTERR] "+msgText+"\n"); abort(); case QtInfoMsg: smartPrintDebugMessage("[INF] "+msgText+"\n"); break; } } void LogHelper::smartPrintDebugMessage(QString msg) { // Подготовка текста для вывода QTime currTime = QTime::currentTime(); QString timeText = currTime.toString("hh:mm:ss.zzz"); msg=timeText+" "+msg; // Быстрый вывод в консоль printf("%s", qPrintable(msg)); } void LogHelper::setDebugMessageHandler() { ... // Устанавливается Qt-обработчик консольного вывода qInstallMessageHandler(ourDebugPrintFunction); } Проблема здесь в том, что "быстрый вывод в консоль" через printf(), в случае окна QtCreator, оказывается совсем не быстрым, а буферизированным. Решается проблема следующим образом: вместо стандартного вывода надо использовать поток ошибок. Приложения Qt, при своем старте, по-умолчанию так настраивают консольный вывод, что поток ошибок stderr попадает в stdout без дополнительных перенаправлений потоков. А отправка сообщений в поток stderr самим QtCreator не буферезируется, и поэтому сообщения появляются без задержки. В официальной документации об этой особенности внятно не сказано, зато в куске кода, который приводится в качестве примера, видно использование функции fprintf() с потоком stderr. Поэтому достаточно вместо строки с printf() написать следующую команду: // Быстрый вывод в консоль fprintf(stderr, "%s", qPrintable(msg)); ... тогда все отладочные сообщения будут появляться в QtCreator без задержки. Примечательно, что если вместо stderr написать stdout, то вывод в окне QtCreator опять станет медленным. В общем, при построении подсистемы вывода лога в консоль, надо учитывать вышеописанную особенность среды QtCreator. |
|||||||
Так же в этом разделе:
|
|||||||
|
|||||||
|