Я пытаюсь глубже понять, как работает буферизация в C
и stdio
, и наткнулся на кое-что интересное. Я прочитал эту статью, но хочу подтвердить, что все правильно понял.
Когда я использую fgets
, устанавливаю буферизацию ввода на 3 байта (stdbuf -i3
) и изучаю strace
, я вижу, что чтение происходит группами по 3 символа, чего я и ожидаю:
read(0, "hel", 3) = 3
read(0, "lo\n", 3) = 3
...
Если я все еще использую stdbuf
, но на этот раз вместо этого делаю системные вызовы read(2)
, он сразу считывает все (до 4096 байт):
read(0, "hello\nworld!\n\n", 4096) = 14
Поэтому он игнорирует вызов stdbuf
.
Это заставляет меня полностью переосмыслить stdio
буферизацию. Поддерживает ли stdio
свой собственный буфер, и stdbuf -i3
говорит, что считывает в этот буфер по 3 байта за раз из буфера основного канала в ядре? Я думал, что выполнение stdbuf -i0
приведет к тому, что емкость канала каким-то образом не сможет удерживать более одного байта (т. Е. Вызовы write(2)
будут блокироваться после 1 байта от процесса, отправляющего stdout
, в небуферизованный процесс stdin
).
Так что было бы правильно сказать, что есть 2 буфера, сидящих поверх фактического буфера канала, которые дополнительно буферизируют stdout
и stdin
? И setbuf
управляет только этими двумя буферами, а не изменяет какие-либо свойства буфера канала ядра. Таким образом, установка stdin
буфера размером n
байтов означает, что он будет хранить n
байтов, прежде чем вернуться к ядру для выполнения системного вызова read
.
stdin
направлен на буферlibc
(который поступает в буфер канала), по сути, гдеSTDIN_FILENO
(или fd 0) направлен непосредственно на конец записи буфера канала, минуя буферlibc
? 16.07.2019cat
без аргументов, она не сможет получить то, что пишется с терминала до новой строки или ctrl+d, потому что ядро буферизует это... А для каналов есть буфер 32-128K внутри ядра 17.07.2019write
не является признаком того, что другой конец прочитал сообщение. 17.07.2019