[英]Is qDebug() thread-safe?
qDebug()
线程安全吗? 通过线程安全我不仅仅意味着不崩溃,而且如果我从不同的线程调用qDebug()
,输出是否可能变得混乱? 我用这个代码测试了它,但它看起来并不是这样,但是,我在文档中的任何地方都找不到它们所讨论的内容。
这是我的测试代码:
#include <QtConcurrent>
#include <QApplication>
void print_a() {
for (int ii = 0; ii < 10000; ii++) {
qDebug("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
}
}
void print_b()
{
for (int ii = 0; ii < 10000; ii++) {
qDebug("bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb");
}
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QtConcurrent::run(print_a);
QtConcurrent::run(print_b);
return a.exec();
}
在任何地方都没有'a'和'b'混合在同一行 ,但我仍然不确定它是否100%线程安全......
以下是我的回答和评论:
如果qDebug()的文档没有提到它是否是线程安全的,我们应该假设它不是。 答案可能取决于平台:qDebug()如何在系统级实现(Linux,Windows,...)。
而不是更广泛的线程安全问题,我认为你问的是一个更具体的问题:“在多线程应用程序中使用qDebug()会导致交错输出线吗?” 答案是“是,偶尔。” 正如@dmcontador上面的结果所证明的那样。 如上面的@quetzalcoatl所解释的那样,当要打印的字符串越来越长时,概率就会增加。
答案不取决于你是使用qDebug(“...”)还是qDebug()<<“...”,因为它们最终都会调用系统级实现代码。
使用原始示例代码生成交错输出线并不容易。 所以我创建了一个新的例子,如下所示:
#include <QCoreApplication> #include <QtConcurrent> #define MAX_ITERS 10 #define MAX_LEN 10000 void print_a() { QString a(MAX_LEN, 'a'); for(int i = 0; i < MAX_ITERS; ++i) { qDebug().noquote() << a; } } void print_b() { QString b(MAX_LEN, 'b'); for(int i = 0; i < MAX_ITERS; ++i) { qDebug().noquote() << b; } } int main(int argc, char * argv[]) { QCoreApplication a(argc, argv); QtConcurrent::run(print_a); QtConcurrent::run(print_b); return 0; }
增加MAX_LEN时概率会增加。
文档说如果函数未标记为线程安全或可重入,则不应在不同的线程中使用它 。 在qDebug()
情况下,它说: Note: This function is thread-safe
。
( 这个答案已经更新......文档没有声明该函数之前是线程安全的。 )
我担心它不是线程安全的。 此外,我尝试了你的代码并混合输出。
aaaaaaaaaaaabbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbabbbbbbbbbbbbbbbbbb
我和qDebug() << "..."
有同样的运气qDebug() << "..."
使用mingw48_32编译器在Qt5.2.1中进行了测试。
我找到了这样的东西: http : //www.qtcentre.org/threads/28879-redirecting-qDebug-to-file-threading-question
引用:
要回答qdebug是线程安全的问题:QDebug使用QTextstream。 QTextStream不是线程安全的。 文档不清楚这一点,但是如果你看一下qdebug或qtextstream的源代码,你会发现代码中根本没有互斥锁。
实际上qDebug( ..text.. )
是线程安全的(至少如果使用gcc编译)。
如果你查看qt(4)源文件qglobal.cpp
, qDebug
调用qt_message_output
调用fprintf(stderr, ...)
,这在glibc中是线程安全的
( qDebug() << ..
是另一个故事)
实际上,QtDebug相关函数(例如qDebug(),qWarning()等)的作用是调用消息处理程序,可以通过调用qInstallMessageHandler()来设置。 所以这取决于你 - 这个消息处理程序是否是线程安全的。 有一个默认实现只是将消息打印到stderr,它不会阻止来自不同线程的混合输出,因此,如果您希望始终为调试消息提供非混合的逐行输出,来自不同的警告和错误线程,您应该安装自己的处理程序与某种锁定(如QMutex),如下所示:
QMutex messageMutex;
void myMessageHandler(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
QMutexLocker locker(&messageMutex);
[print msg and context somewhere]
}
int main(int argc, char **argv)
{
qInstallMessageHandler(myMessageHandler);
QApplication app(argc, argv);
[...]
}
注意 :正如Kuba Ober正确指出的那样,应该谨慎使用(尽管一般情况下都是锁定)。 例如,如果在使用相同的I / O库输出调试消息时从I / O库内部调用QtDebug函数,则可能会出现死锁(例如,当QtDebug消息处理程序在持有锁时调用I / O时,这是可能的在非递归互斥体上,然后底层I / O机制调用一些回调函数,然后这个回调函数调用QtDebug函数,它再次调用相同的处理程序)。
都
qDebug("xx")
以及
qDebug() << "xx"
qInfo,qWarning,qCritical以及qCDebug,qCInfo,qCWarning,qCritical等分类版本可以安全地从不同的线程中同时使用。
但是,您必须确保日志接收器还可以原子方式处理大数据。 这是混乱来自,因为stderr显然打破了太长的线。 您可以通过在示例中用fprintf(stderr)替换qDebug()来轻松验证这一点:它为我显示完全相同的行为。
您可以尝试其他日志记录接收器,例如journald。 无论如何,他们也可能对最大长度施加限制。 一般来说,我建议保持日志消息的最大长度合理。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.