我几天前开始使用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 :(得分:3)
在Qt文档中找不到qDebug
是线程安全的。因此,从多个线程同时调用它是不安全的,如果你不使用锁定机制,你会遇到混合输出。
如果你使用QMutexLocker
,你的锁定方法会更好,因为Qt文档强烈建议:
void MessageHandler(QtMsgType type, const QMessageLogContext & context, const QString & msg)
{
QMutexLocker locker(&mutex);
...
}
第二种方法是提供具有用于写入日志的槽的工作者类。然后,您可以在新线程中拥有它的实例,并使用QMetaObject::invokeMethod
连接类型Qt::QueuedConnection
在消息处理程序中调用它的插槽。这样,来自每个线程的每个调用都将排队并在工作线程中进行处理,因为所有工作都在一个单独的线程中完成,所以它可能会有更好的性能。
答案 1 :(得分:2)
您的方法看起来简单干净。我保持这样。
您可以改进一件事:在应用程序启动时只打开一次文件,关闭应用程序时关闭它。打开文件是一项昂贵的操作。
您可以从多个线程写入相同的打开文件,因为您的互斥锁确保只有一个线程同时写入。
答案 2 :(得分:0)
我没有收到关于您对呆滞现象的担忧的回复,我敢肯定,这次您已经找到了答案。您可以通过减少关键区域内的代码量来提高性能。文件操作很慢,因此请尝试减少花费的时间。这可以包括保持文件打开状态,缓冲日志并定期写入,在锁定区域之外构造条目以及
void MessageHandler(QtMsgType type, const QMessageLogContext & context, const QString & msg)
{
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));
QString entryString("%1 %2: %3");
entryString = entryString.arg(timeStr).arg(contextString).arg(msg);
QFile outFile("file.log");
mutex.lock();
outFile.open(QIODevice::WriteOnly | QIODevice::Append);
QTextStream stream(&outFile);
stream << entryString << endl;
mutex.unlock();
}