Является ли 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% потокобезопасный …

23

Решение

Ниже приведены мой ответ и комментарии:

  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 () для получения не чередующихся выходных строк?» Одним из решений было бы использовать QMutex в каждой строке qDebug (). Обратите внимание, что я не пробовал это решение, которое не практично.
14

Другие решения

Документы говорят Если функция не помечена как поточно-ориентированная или реентерабельная, ее не следует использовать из разных потоков. В случае qDebug() он не говорит, что он потокобезопасен или реентерабелен, поэтому его, вероятно, небезопасно использовать из разных потоков.

11

Я боюсь, что это не потокобезопасно. Кроме того, я попробовал ваш код и имел смешанный вывод.

aaaaaaaaaaaabbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbabbbbbbbbbbbbbbbbbb

Мне повезло с qDebug() << "..."

Протестировано в Qt5.2.1 с компилятором mingw48_32.

8

Я нашел такую ​​вещь: http://www.qtcentre.org/threads/28879-redirecting-qDebug-to-file-threading-question

Цитирование:

Чтобы ответить на вопрос, является ли qdebug потокобезопасным:
QDebug использует QTextstream. QTextStream не является потокобезопасным.
В документации не ясно об этом, но если вы посмотрите на исходный код qdebug или qtextstream, то увидите, что в коде вообще нет блокировки мьютекса.

2

Практически qDebug( ..text.. ) Потокобезопасен (по крайней мере, если скомпилирован с GCC).

Если вы посмотрите в исходном файле qt (4) qglobal.cpp, qDebug звонки qt_message_output какие звонки fprintf(stderr, ...), который является потокобезопасным в glibc

(qDebug() << .. это другая история)

2

И то и другое

qDebug("xx")

так же как

qDebug() << "xx"

qInfo, qWarning, qCritical и классифицированные версии, такие как qCDebug, qCInfo, qCWarning, qCritical, безопасны для одновременного использования из разных потоков.

Однако вы должны убедиться, что приемник журналов может также обрабатывать большие данные атомарно. Отсюда и путаница, потому что stderr явно ломает слишком длинную строку. Вы можете легко проверить это, просто заменив qDebug () на fprintf (stderr) в примере: он показывает точно такое же поведение для меня.

Вы можете попробовать другие приемники, например journald. В любом случае, они могут также накладывать ограничения на максимальную длину. В общем, я бы посоветовал сохранить максимальную длину лог-сообщения разумной.

0
По вопросам рекламы [email protected]