2015-04-04 2 views
8

Я начал использовать Qt5 несколько дней назад. Мне нужно было logger для моего приложения, и я решил использовать qDebug, но, похоже, он должен быть «перенаправлен», чтобы иметь журналы в файле.Qt5: Как использовать qDebug() для входа в файл, многопоточного приложения

Я использовал qInstallMessageHandler, чтобы сделать это, и я написал свой собственный обработчик, как показано ниже (вдохновленный другими людьми здесь).

Кажется, что это работает, но поскольку я не гуру, я должен спросить: Можно ли использовать это в многопоточном приложении или нет?

Кроме того, если это нормально/безопасно для использования в приложении с несколькими потоками, можете ли это как-то улучшить?
Спасибо!

void MessageHandler(QtMsgType type, const QMessageLogContext & context, const QString & msg) 
{ 
    mutex.lock(); 

    QDateTime dateTime(QDateTime::currentDateTime()); 

    QString timeStr(dateTime.toString("dd-MM-yyyy HH:mm:ss:zzz")); 
    QString contextString(QString("(%1, %2)").arg(context.file).arg(context.line)); 

    QFile outFile("file.log"); 
    outFile.open(QIODevice::WriteOnly | QIODevice::Append); 

    QTextStream stream(&outFile); 
    stream << timeStr << " " << contextString << ": " << msg << endl; 

    mutex.unlock(); 
} 
+0

У какого типа есть переменная 'mutex'? –

+0

статический мьютекс QMutex; // глобальная переменная –

+0

Для какой ОС вы разрабатываете? –

ответ

1

Ваш подход выглядит простым и чистым. Я бы сохранил это так.

Есть одна вещь, которую вы можете улучшить: открыть файл только один раз при запуске приложения и закрыть его при закрытии приложения. Открытие файла - дорогостоящая операция.

Вы можете писать в один и тот же открытый файл из нескольких потоков, так как ваш мьютекс гарантирует, что одновременно будет записываться только один поток.

+0

Simon, спасибо, что нашли время и для вашего совета! Я бы открыл файл только один раз при запуске, но (в самом ближайшем будущем) я планирую изменить имя файла из «file.log» на что-то вроде «dd-mm-yyy.log» ... Я конечно, вы знаете, что я имею в виду :) Итак, было бы невозможно открыть файл журнала при запуске приложения ... Любая идея/обходной путь для этой проблемы? Заранее спасибо! –

+0

@groenhen Ожидаете ли вы, что приложение работает более одного дня? –

+0

Да, он будет работать без остановок (по крайней мере, я так надеюсь:) ...) –

2

Вы не можете найти где-нибудь в документации Qt, что qDebug потокобезопасно. Поэтому небезопасно вызывать его одновременно из нескольких потоков, и действительно, вы столкнетесь с смешанным выходом, если не используете механизм блокировки.

Ваш замок подход был бы лучше, если вы используете QMutexLocker, как настоятельно рекомендуется в документации Qt:

void MessageHandler(QtMsgType type, const QMessageLogContext & context, const QString & msg) 
{ 
    QMutexLocker locker(&mutex); 
    ... 
} 

Второй подход заключается в создании класса работник, который имеет слоты для записи журнала. Затем вы можете иметь экземпляр этого в новом потоке и вызвать его слоты в обработчике сообщений, используя QMetaObject::invokeMethod с типом соединения Qt::QueuedConnection. Таким образом, каждый вызов из каждого потока будет поставлен в очередь и обработан в рабочем потоке, и, вероятно, он будет иметь лучшую производительность, поскольку вся работа выполняется в отдельном потоке.

+1

Но AFAIK, «Шкаф QMutexLocker (& mutex);» выполняет ту же работу, что и mutex.lock(), за которой следует mutex.unlock(), единственное отличие состоит в том, что вам не нужно беспокоиться, если/когда эта функция/метод имеет несколько точек выхода/возврата. Мьютекс будет автоматически разблокирован при выходе, поскольку блокиратор является автоматической переменной. С уважением, С.Г. –

+0

BTW: Как насчет «с точки зрения скорости» ...? Какой из них выполняется быстрее, блокировка/разблокировка мьютекса() или механизм QMutexLocker? –

+0

Я не знаю, отличаются ли они по скорости. Но второй подход состоит в том, чтобы иметь рабочий поток и выполнять операции там. См. Отредактированный ответ. – Nejat

Смежные вопросы