繁体   English   中英

qDebug()线程安全吗?

[英]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%线程安全......

以下是我的回答和评论:

  1. 如果qDebug()的文档没有提到它是否是线程安全的,我们应该假设它不是。 答案可能取决于平台:qDebug()如何在系统级实现(Linux,Windows,...)。

  2. 而不是更广泛的线程安全问题,我认为你问的是一个更具体的问题:“在多线程应用程序中使用qDebug()会导致交错输出线吗?” 答案是“是,偶尔。” 正如@dmcontador上面的结果所证明的那样。 如上面的@quetzalcoatl所解释的那样,当要打印的字符串越来越长时,概率就会增加。

  3. 答案不取决于你是使用qDebug(“...”)还是qDebug()<<“...”,因为它们最终都会调用系统级实现代码。

  4. 使用原始示例代码生成交错输出线并不容易。 所以我创建了一个新的例子,如下所示:

     #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时概率会增加。

  1. 后续问题是:“如何使用qDebug()生成非交错输出线?” 一种解决方案是在每个qDebug()行上使用QMutex。 请注意,我没有尝试过这种不实用的解决方案。

文档说如果函数未标记为线程安全或可重入,则不应在不同的线程中使用它 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.cppqDebug调用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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM