qDebug() 线程安全吗?



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() << "..."运气一样

在Qt5.2.1中使用mingw48_32编译器进行了测试。

事实上,与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 函数, 再次调用同一处理程序(。

我发现了这样的事情: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() << ..是另一回事(

两者

qDebug("xx")

以及

qDebug() << "xx"

qInfo,qWarning,qCritical和分类版本如qCDebug,qCInfo,qCWarning,qCritical可以安全地从不同的线程同时使用。

但是,必须确保日志接收器也可以原子方式处理大型数据。这就是混乱的来源,因为stderr显然打破了太长的行。您可以通过在示例中将 qDebug(( 替换为 fprintf(stderr( 来轻松验证这一点:它为我显示了完全相同的行为。

可以尝试其他日志记录接收器,例如日志。无论如何,他们也可能对最大长度施加限制。一般来说,我建议保持日志消息的最大长度合理。

相关内容

  • 没有找到相关文章

最新更新