Согласно стандартам, упомянутый вами цикл for не является допустимой реализацией writev
по нескольким причинам:
- Цикл может не завершить запись одного iov, прежде чем перейти к следующему, в случае короткой записи - но это можно обойти, сделав цикл более сложным.
- Цикл может иметь неправильное поведение в отношении атомарности для каналов: если общая длина записи меньше, чем
PIPE_BUF
, запись в канал должна быть атомарной, но цикл нарушит требование атомарности. Эту проблему нельзя обойти, кроме как путем перемещения всех записей iov в один буфер перед записью, когда общая длина не превышает PIPE_BUF
.
- Цикл может иметь случаи, когда он может привести к блокировке, когда для выполнения частичной записи без блокировки потребуется один вызов
writev
. Насколько я знаю, эту проблему невозможно обойти в общем случае.
- Возможно, другие причины, о которых я не задумывался.
Я не уверен насчет пункта № 3, но он определенно существует в противоположном направлении при чтении. Вызов read
в цикле может блокироваться, если у терминала есть некоторые данные (короче, чем общая длина IOV), за которыми следует индикатор EOF; вызов readv
должен немедленно вернуться с частичным чтением в этом случае. Однако, из-за ошибки в Linux, readv
на терминалах фактически реализован как цикл read
в пространстве ядра, и он демонстрирует эту блокирующую ошибку. Мне пришлось обойти эту ошибку при реализации stl musl:
http://git.etalabs.net/cgi-bin/gitweb.cgi?p=musl;a=commit;h=2cff36a84f268c09f4c9dc5a1340652c8e298dc0
Чтобы ответить на последнюю часть вашего вопроса:
Или writev
записывает все в файл за один вызов ввода-вывода?
Во всех случаях совместимая реализация writev
будет представлять собой один системный вызов. Переходя к тому, как это реализовано в Linux: для обычных файлов и для большинства устройств базовый файловый драйвер имеет методы, которые реализуют io в стиле iov напрямую, без какого-либо внутреннего цикла. Но драйвер терминала в Linux сильно устарел и не имеет современных методов ввода-вывода, из-за чего ядро возвращается к циклу записи / чтения для writev
/ readv
при работе на терминале.