Безопасна ли реализация MSVCRT потока fprintf()?
Кажется, что реализация glibc функции fprintf() является поточно-ориентированной, но так ли это и для CRT от Microsoft?
Под поточно-ориентированным я имею в виду не только сбой, но и то, что если несколько потоков (в одном процессе) вызывают fprintf()
Тексты не будут смешиваться.
Это, например, если поток A вызывает fprintf(stdout, "aaaa");
и поток B звонит fprintf(stdout, "bbbb");
гарантированно не смешиваться, чтобы стать aabbaabb
,
Есть ли такая гарантия?
1 ответ
Да. В многопоточных библиотеках времени выполнения каждый поток имеет связанную блокировку. Эта блокировка получается в начале любого вызова функции printf и не снимается до тех пор, пока не вернется эта функция printf.
Такое поведение требуется C11 (в стандарте C до C11 не было понятия "нити"). C11 §7.21.2/7-8 гласит:
Каждый поток имеет связанную блокировку, которая используется для предотвращения гонок данных, когда несколько потоков выполнения обращаются к потоку, и для ограничения чередования потоковых операций, выполняемых несколькими потоками. Только один поток может удерживать эту блокировку одновременно. Блокировка реентерабельна: один поток может удерживать блокировку несколько раз в данный момент времени.
Все функции, которые читают, пишут, позиционируют или запрашивают позицию потока, блокируют поток перед доступом к нему. Они снимают блокировку, связанную с потоком, когда доступ завершен.
Visual C++ не полностью поддерживает C11, но соответствует этому требованию. Пара других специфичных для Visual C++ комментариев:
Пока вы не определяете _CRT_DISABLE_PERFCRIT_LOCKS
(который работает только со статически связанными библиотеками времени выполнения, libcmt.lib и друзьями) или с использованием функций с суффиксом _nolock, тогда большинство операций в одном потоке являются атомарными.
Если вам требуется атомарность для нескольких операций в потоке, вы можете получить блокировку для файла самостоятельно, получив и сняв блокировку потока самостоятельно, используя _lock_file
а также _unlock_file
,