【问题标题】:Can Qt library components call qDebug() or simmilar?Qt 库组件可以调用 qDebug() 或类似的吗?
【发布时间】:2016-06-24 10:27:51
【问题描述】:

我使用qInstallMessageHandler 注册自定义日志记录功能。此函数格式化消息(例如,它添加时间戳)并将其打印到控制台和日志文件。

我担心的是,如果 Qt 库组件(如 QDateTimeQDirQFile...)可以调用 qDebug()qWarning() 等?

如果是,这可能会导致无限递归……

【问题讨论】:

  • 是的,Qt 本身使用那些调试/警告工具,所以你需要保护自己。

标签: c++ qt qdebug


【解决方案1】:

简单的答案是:避免重新输入您的消息处理程序,然后:

// C++11, Qt 5.4+
void myMessageHandler(…) {
  thread_local bool entered = false;
  if (entered) return; // oops
  QScopedValueRollback set{entered, true};
  …
}

// C++11, Qt 4.8+
void myMessageHandler(…) {
  thread_local bool entered = false;
  if (entered) return; // oops
  QScopedValueRollback back{entered};
  entered = true;
  …
}

// C++98, Qt 4
QThreadStorage<bool> entered;
void myMessageHandler(…) {
  if (entered.localData()) return;
  QScopedValueRollback back(entered.localData());
  entered.localData() = true;
  …
}

对于后代来说,这是一个古老而愚蠢的答案:

仅当您的日志记录是同步的时才会导致无限递归。一旦您使日志记录异步,您就不会再遇到问题了:消息处理程序将永远不会被重新输入,因为您在发出信号后立即退出它,并且通过排队连接的信号发射发布零或更多 QMetaCallEvent 实例到相关线程的事件队列中,仅此而已。

异步日志记录是通过在消息处理程序中发出信号来实现的,并通过显式排队连接处理从连接到信号的槽/函子的日志写入。您可能希望您的记录器驻留在自己的线程中,因此这是一种非常自然的方法并且效果很好。

【讨论】:

  • 好主意!谢谢你。什么物体应该发出这个信号?可以举个例子吗?
  • @user2449761 当然是专门为此目的制作的对象。一个辅助对象,如果你愿意的话。可以是全局单例,在应用实例创建前分配在main()中。
  • 异步日志对象不会创建递归,而是无限增长的事件队列。这更难检测
  • @user2449761 为什么会创建一个无限增长的事件队列?你应该为这些事件服务:)
  • 类似于递归。当我在异步任务(线程)中处理“日志事件”时,某些 Q* 对象可能会使用 QDebug() 来打印一些警告。这将导致另一个日志事件,并且同一个对象可能想再次使用 QDebug() ,一次又一次......并且队列可能会无限增长。我知道这不太可能发生(Qt 对象不是很冗长),但我的发现是不应在消息处理程序(同步或异步)中使用 Qt 对象。
猜你喜欢
  • 2018-12-26
  • 1970-01-01
  • 2015-08-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-10-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多