c++multithreadingqtqdebug

Is qDebug() thread-safe?


Is qDebug() thread-safe? By thread-safe I don't just mean not-crashing, but also if I call qDebug() from different threads, is it possible for the output to become mixed-up? I tested it with this code, and it doesn't appear to be so, however, I couldn't find anywhere in the documentation where they talk about this.

This is my test code:

#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();
}

There were no 'a' and 'b' mixed in the same line anywhere, but I'm still not sure if it's 100% thread safe...


Solution

  • Following are my answer and comments:

    1. If the documentation of qDebug() does not mention whether it is thread-safe or not, we should assume it is not. The answer is likely platform-dependent: how qDebug() is implemented at the system level (Linux, Windows, ...).

    2. Instead of the broader question of thread-safety, I think you were asking a more specific question like this: "Will the use of qDebug() in a multi-threaded application lead to interleaved output lines?" The answer is "Yes, occasionally." as demonstrated by the results produced by @dmcontador above. And the probability increases when the strings to be printed out are getting longer, as explained by @quetzalcoatl above.

    3. The answer does not depend on whether you use qDebug("...") or qDebug() << "...", as both will finally call the system-level implementation code.

    4. It is not easy for me to produce interleaved output lines using your original example code. So I have created a new example as shown below:

      #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;
      }
      

    The probability increases when you increase MAX_LEN.

    1. A follow-up question would be: "How to use qDebug() to produce non-interleaved output lines?" One solution would be to use QMutex on each and every qDebug() line. Note that I have not tried this solution which is not practical.