Является 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()
он не говорит, что он потокобезопасен или реентерабелен, поэтому его, вероятно, небезопасно использовать из разных потоков.
Я боюсь, что это не потокобезопасно. Кроме того, я попробовал ваш код и имел смешанный вывод.
aaaaaaaaaaaabbbbbaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbabbbbbbbbbbbbbbbbbb
Мне повезло с qDebug() << "..."
Протестировано в Qt5.2.1 с компилятором mingw48_32.
Я нашел такую вещь: 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() << ..
это другая история)
И то и другое
qDebug("xx")
так же как
qDebug() << "xx"
qInfo, qWarning, qCritical и классифицированные версии, такие как qCDebug, qCInfo, qCWarning, qCritical, безопасны для одновременного использования из разных потоков.
Однако вы должны убедиться, что приемник журналов может также обрабатывать большие данные атомарно. Отсюда и путаница, потому что stderr явно ломает слишком длинную строку. Вы можете легко проверить это, просто заменив qDebug () на fprintf (stderr) в примере: он показывает точно такое же поведение для меня.
Вы можете попробовать другие приемники, например journald. В любом случае, они могут также накладывать ограничения на максимальную длину. В общем, я бы посоветовал сохранить максимальную длину лог-сообщения разумной.