Nano Hash - криптовалюты, майнинг, программирование

setbuf влияет только на вызовы stdio, а не на системные вызовы?

Я пытаюсь глубже понять, как работает буферизация в 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.

16.07.2019

Ответы:


1

Буферизация существует только внутри libc, функции, которые вы вызываете из stdio. На интерфейсе системного вызова нет буферизации. Если вы делаете системный вызов (используя, например, read или write), обычно очень мало что делают оболочки libc перед вызовом ядра.

В документации для stdbuf говорится

command должно начинаться с имени программы, которая... использует потоки ISO C FILE для ввода/вывода (обратите внимание, что программы dd и cat этого не делают),

Это связано с тем, что stdbuf работает путем предварительной загрузки библиотеки в целевая программа, которая изменяет режим буферизации (в своей libc). Программа, которая делает прямые системные вызовы, не затрагивается.

stdbuf не меняет размер буфера каналов в ядре. Этот буфер не связан с буферизацией, предоставляемой libc.


Поддерживает ли stdio свой собственный буфер, а stdbuf -i3 говорит считывать в этот буфер по 3 байта за раз из буфера основного канала в ядре?

Да. Libc предоставляет буферы для потоков stdio.h FILE.

16.07.2019
  • Благодарю вас! Правильно ли будет тогда сказать, что stdin направлен на буфер libc (который поступает в буфер канала), по сути, где STDIN_FILENO (или fd 0) направлен непосредственно на конец записи буфера канала, минуя буфер libc? 16.07.2019
  • Ядро может иметь и имеет свои собственные буферы! 16.07.2019
  • @AnttiHaapala это означает, что я не могу гарантировать небуферизованное чтение или запись при выполнении системных вызовов? Судя по тому, что я читал, большая разница между STDIN и STDIN_FILENO заключается в том, что первый буферизуется, а второй нет. Но, может быть, они просто имеют в виду, что первый буферизуется stdio позже? 17.07.2019
  • Да... В ядре, например, всегда были буферы для каналов и терминалов. Даже если вы запустите программу типа cat без аргументов, она не сможет получить то, что пишется с терминала до новой строки или ctrl+d, потому что ядро ​​буферизует это... А для каналов есть буфер 32-128K внутри ядра 17.07.2019
  • @АнттиХаапала, спасибо! Итак, чтобы уточнить, это означает, что когда я выполняю системный вызов записи, возможно, что данные не будут сразу доступны на считывающем конце канала? Если это действительно так, то как сделать так, чтобы все операции записи в программе были немедленно доступны для чтения в конце канала? 17.07.2019
  • Буферизация обычно означает, что данные доступны немедленно, однако возврат write не является признаком того, что другой конец прочитал сообщение. 17.07.2019
  • @AntiHaapala, конечно. Итак, вот где я немного запутался, если записи сразу доступны для чтения конца канала, и терминал должен был сделать системный вызов записи для каждого записанного символа, не будет ли блокировка программы при вызове чтения на приеме конец трубы (например, кошка) немедленно получить эти данные? Или системный вызов записи с терминала происходит только при EOF/новой строке? 17.07.2019
  • Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

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

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..