В общем, я предполагаю, что потоки не синхронизируются, пользователь должен выполнить соответствующую блокировку. Однако есть ли cout
особая обработка в стандартной библиотеке?
То есть, если несколько потоков пишут, cout
могут ли они повредить cout
объект? Я понимаю, что даже при синхронизации вы все равно получите произвольно чередующийся вывод, но гарантировано ли это чередование. То есть безопасно ли использовать cout
из нескольких потоков?
Зависит ли этот поставщик? Что делает gcc?
Важно : дайте ссылку на свой ответ, если вы скажете «да», поскольку мне нужно какое-то доказательство этого.
Меня беспокоят также не основные системные вызовы, это нормально, но потоки добавляют слой буферизации поверх.
printf
сияет, поскольку весь вывод записываетсяstdout
одним выстрелом; при использованииstd::cout
каждого звена цепочки выражений будет выводиться отдельно вstdout
; между ними может быть какой-то другой поток записи,stdout
из-за которого порядок конечного вывода нарушается.Ответы:
Стандарт C ++ 03 об этом ничего не говорит. Если у вас нет гарантий относительно потоковой безопасности чего-либо, вы должны относиться к этому как к небезопасному для потоков.
Особый интерес здесь представляет то, что
cout
буферизуется. Даже если вызовыwrite
(или что-то еще, что обеспечивает этот эффект в этой конкретной реализации) гарантированно являются взаимоисключающими, буфер может совместно использоваться разными потоками. Это быстро приведет к повреждению внутреннего состояния потока.И даже если доступ к буферу гарантированно будет потокобезопасным, что, по вашему мнению, произойдет в этом коде?
Вероятно, вы хотите, чтобы каждая линия здесь действовала во взаимоисключающем режиме. Но как реализация может гарантировать это?
В C ++ 11 есть некоторые гарантии. FDIS говорит следующее в §27.4.1 [iostream.objects.overview]:
Таким образом, вы не получите поврежденные потоки, но вам все равно придется синхронизировать их вручную, если вы не хотите, чтобы вывод был мусором.
источник
cout.sync_with_stdio()
это правда, использованиеcout
для вывода символов из нескольких потоков без дополнительной синхронизации четко определено, но только на уровне отдельных байтов. Таким образом,cout << "ab";
иcout << "cd"
выполняемые в разных потоках могут выводитьacdb
, например, но не могут вызывать Undefined Behavior.Это большой вопрос.
Во-первых, C ++ 98 / C ++ 03 не имеет понятия «поток». Так что в том мире вопрос бессмысленный.
А как насчет C ++ 0x? См . Ответ Мартиньо (который, признаюсь, меня удивил).
Как насчет конкретных реализаций до C ++ 0x? Ну, например, вот исходный код для
basic_streambuf<...>:sputc
GCC 4.5.2 (заголовок "streambuf"):Ясно, что это не приводит к блокировке. И ни то, ни другое
xsputn
. И это определенно тот тип streambuf, который использует cout.Насколько я могу судить, libstdc ++ не блокирует ни одну из потоковых операций. И я бы не ожидал, что это будет медленно.
Таким образом, с этой реализацией очевидно, что выход двух потоков может повредить друг друга (а не только чередоваться).
Может ли этот код повредить саму структуру данных? Ответ зависит от возможных взаимодействий этих функций; например, что произойдет, если один поток пытается очистить буфер, а другой пытается вызвать
xsputn
или что-то еще. Это может зависеть от того, как ваш компилятор и процессор решат переупорядочить загрузку и хранение памяти; для уверенности потребуется тщательный анализ. Это также зависит от того, что делает ваш процессор, если два потока одновременно пытаются изменить одно и то же местоположение.Другими словами, даже если он нормально работает в вашей текущей среде, он может выйти из строя, когда вы обновите любую среду выполнения, компилятор или процессор.
Резюме: «Я бы не стал». Создайте класс ведения журнала, который выполняет правильную блокировку, или перейдите на C ++ 0x.
В качестве слабой альтернативы вы можете установить для cout значение без буферизации. Вероятно (хотя и не гарантируется), что вся логика, связанная с буфером, будет пропущена и будет выполняться
write
прямой вызов . Хотя это может быть слишком медленно.источник
cout
.www.techrepublic.com/article/use-stl-streams-for-easy-c-plus-plus-thread-safe-logging
а также: Являются ли стандартные потоки вывода в C ++ потокобезопасными (cout, cerr, clog)?
ОБНОВИТЬ
Пожалуйста, посмотрите ответ @Martinho Fernandes, чтобы узнать, что говорит об этом новый стандарт C ++ 11.
источник
Как упоминается в других ответах, это определенно зависит от поставщика, поскольку стандарт C ++ не упоминает о потоковой передаче (это изменяется в C ++ 0x).
GCC не дает много обещаний относительно безопасности потоков и ввода-вывода. Но документация по обещаниям находится здесь:
Ключевым моментом, вероятно, является:
Не знаю, изменилось ли что-нибудь в упомянутом таймфрейме 3.0.
Документацию по безопасности потоков MSVC для
iostreams
можно найти здесь: http://msdn.microsoft.com/en-us/library/c9ceah3b.aspx :Обратите внимание, что эта информация относится к самой последней версии MSVC (в настоящее время для VS 2010 / MSVC 10 /
cl.exe
16.x). Вы можете выбрать информацию для более старых версий MSVC, используя раскрывающийся список на странице (а для более старых версий информация отличается).источник