MyTetra Share
Делитесь знаниями!
Что делать, если сообщения в консоли 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.


Так же в этом разделе:
 
MyTetra Share v.0.60
Яндекс индекс цитирования