stackoverflow.com/questions/3941271/...

в стандартный выводprintf поточно-ориентированный на Linux? Как насчет использования нижнего уровняwrite команда?

Ответы на вопрос(5)

зависит от вашего определения «потокобезопасности». POSIX требуетstdio использовать функции блокировки, чтобы ваша программа не зависала,FILE состояния объекта и т. д., если вы используетеprintf одновременно из нескольких потоков.Однако всеstdio операции формально определены в терминах повторных обращений кfgetc а такжеfputcТаким образом, не гарантируется атомарность в более широком масштабе. То есть, если потоки 1 и 2 пытаются напечатать"Hello\n" а также"Goodbye\n" в то же время, нет никакой гарантии, что выход будет либо"Hello\nGoodbye\n" или же"Goodbye\nHello\n", С таким же успехом может быть"HGelolodboy\ne\n", На практике большинство реализаций получит одну блокировку для всего вызова записи более высокого уровня просто потому, что это более эффективно, но ваша программа не должна этого допускать. Могут быть угловые случаи, когда это не сделано; например, реализация может, вероятно, полностью исключить блокировку небуферизованных потоков.

Редактировать: Приведенный выше текст об атомности неверен. POSIX гарантирует всеstdio операции являются атомарными, но гарантия скрыта в документации дляflockfile: http://pubs.opengroup.org/onlinepubs/9699919799/functions/flockfile.html

Все функции, которые ссылаются на объекты (FILE *), должны вести себя так, как будто они используют flockfile () и funlockfile () для получения прав собственности на эти объекты (FILE *).

Вы можете использоватьflockfile, ftrylockfile, а такжеfunlockfile функционирует самостоятельно для достижения атомарной записи, превышающей единичный вызов функции.

так как этот вопрос был задан (и последний ответ).

C11 теперь поставляется с поддержкой многопоточности и обращается к многопоточному поведению потоков:

§7.21.2 Потоки

¶7 Каждый поток имеет связанную блокировку, которая используется дляпредотвратить гонки данных когда несколько потоков выполнения обращаются к потоку, иограничить перемежение потоковых операций, выполняемых несколькими потоками. Только один поток может удерживать эту блокировку одновременно. Блокировка реентерабельна: один поток может удерживать блокировку несколько раз в данный момент времени.

¶8 Все функции, которые читают, пишут, позиционируют или запрашивают позицию потока, блокируют поток перед доступом к нему. Они снимают блокировку, связанную с потоком, когда доступ завершен.

Таким образом, реализация с потоками C11 должна гарантировать, что использованиеprintf потокобезопасен.

Ли атомарность (как в нет чередования1) гарантировано, на первый взгляд мне это было не понятно, потому что стандартограничение чередование, в отличие отпредотвращение, который он поручил для данных гонок.

Я склоняюсь к тому, чтобы быть гарантированным. Стандарт говорит оограничение чередование, так как допускается некоторое чередование, которое не меняет результат;например fwrite несколько байтов,fseek назад еще немного иfwrite до исходного смещения, так что обаfwrites спина к спине. Реализация может свободно изменить порядок этих 2fwriteи объединить их в одну запись.

1: См. Зачеркнутый текст вR .. ответ для примера.

что ваше приложение не потерпит крах, если несколько потоков вызовут их по одному и тому же дескриптору файла. Однако без некоторой блокировки на уровне приложения все, что написано, может чередоваться.

Решение Вопроса

артной библиотеки C. Фактически, в стандарте C даже не упоминаются потоки, поскольку некоторые системы (например, встроенные системы) не имеют многопоточности.

В реализации GNU (glibc), большинство функций более высокого уровня в stdio, которые имеют дело сFILE* объекты потокобезопасны. Те, которые обычно не имеютunlocked в их именах (например,getc_unlocked(3)). Однако безопасность потока находится на уровне вызова для каждой функции: если вы делаете несколько вызововprintf(3)Например, каждый из этих вызовов гарантированно выводится атомарно, но другие потоки могут распечатывать вещи между вашими вызовамиprintf(), Если вы хотите, чтобы последовательность вызовов ввода / вывода выводилась атомарно, вы можете окружить их паройflockfile(3)/funlockfile(3) звонки, чтобы заблокироватьFILE ручка. Обратите внимание, что эти функции являются реентерабельными, поэтому вы можете безопасноprintf() между ними, и это не приведет к тупику, даже мысльprintf() сам звонитflockfile().

Низкоуровневые вызовы ввода / вывода, такие какwrite(2) должен быть потокобезопасным, но я не уверен на 100% в этом -write() делает системный вызов в ядре для выполнения ввода-вывода. Как именно это происходит, зависит от того, какое ядро ​​вы используете. Это может бытьsysenter инструкция илиint (прерывание) инструкция на старых системах. Оказавшись внутри ядра, это зависит от ядра, чтобы убедиться, что ввод / вывод является потокобезопасным. В тесте, который я только что сделал с версией Darwin Kernel 8.11.1,write(2) кажется потокобезопасным.

 R..26 июл. 2010 г., 15:46
Этот ответ игнорирует, что вопрос был помечен Unix / Linux. POSIX требует, чтобы stdio был потокобезопасным, что весьма прискорбно, поскольку он убивает производительность и поскольку практического способа работы с одним и тем же ФАЙЛОМ из нескольких потоков нет (данные будут безнадежно чередоваться; атомарность существует только на уровне символов).
 DanM02 сент. 2009 г., 17:13
Многопоточность распространена во встроенных системах.
 Nemo05 мар. 2013 г., 19:09
Было бы неплохо обновить этот ответ для C11.
 Adrian Ratnapala01 дек. 2013 г., 07:44
@couling Я думаю, он имеет в виду, что потокобезопасность бесполезна, потому что все равно чередуется, если вы все равно не используете явный файл блокировки f [un].
 nob19 февр. 2013 г., 18:13
Иногда вполне нормально, если вывод чередуется, например, во время регистрации через printf из нескольких потоков.

printf должен быть реентерабельным, и вы не будете вызывать никаких странностей или искажений в вашей программе.

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

 Adam Hawes22 янв. 2009 г., 22:54
Я не знаю, что делают другие, но библиотека GNU C по умолчанию ориентирована на многопотоковое исполнение, поэтому нет, она не будет использовать тот же буфер.
 Martin Beckett22 янв. 2009 г., 05:04
Все вызовы printf могут использовать один и тот же буфер для построения строки. Многие реализации также совместно используют буфер между scanf и printf, что может вызвать некоторые странные ошибки, связанные с отладкой.
 Yu Hao03 июн. 2013 г., 08:05
Я не думаюprintf реентерабельный, см.stackoverflow.com/questions/3941271/...

Ваш ответ на вопрос