SETIOV(iov + 0, &header, sizeof(header.io_write));
SETIOV(iov + 1, &cache_buffer[37], 4096);
SETIOV(iov + 2, &cache_buffer[16], 4096);
SETIOV(iov + 3, &cache_buffer[22], 4096);
rcvid = MsgReceivev(chid, iov, 4, NULL);
Эта программа делает в значительной степени то, что вы и предполагаете: она задает вектор IOV из 4 частей, первая из которых указывает на заголовок, а следующие три части — на блоки кэш-памяти с номерами 37, 16 и 22. (Предположим, что именно эти блоки случайно оказались доступными в данный момент.) Ниже это иллюстрируется графически.
Распределение непрерывных данных по отдельным буферам.
Затем осуществляется вызов функции
(Кроме возможности работать с векторами IOV, функция
Опа! Мы сделали ту же самую ошибку, которую уже делали к раньше, когда знакомились с функцией
Мы сможем решить эту проблему тем же способом, что и прежде:
rcvid = MsgReceive(chid, &header, sizeof(header), NULL);
switch (header.message_type) {
...
case _IO_WRITE:
number_of_bytes = header.io_write.nbytes;
// Выделить / найти элемент кэша
// Заполнить элементами кэша 3-элементный IOV
MsgReadv(rcvid, iov, 3, sizeof(header.io_write));
Здесь мы вызываем «предварительную» sizeof(header.io_write)
) в кэш-буферы, определенные трехэлементным вектором IOV.
Обратите внимание, что мы перешли от вектора IOV, состоящего из 4 частей (как в первом примере), к вектору IOV из 3 частей. Дело в том, что в первом примере первый из четырех элементов вектора IOV отводился под заголовок, который на этот раз мы считали непосредственно при помощи функции
Можно представить, как мы ответили бы на запрос чтения:
1. Найти элементы кэша, которые соответствуют запрашиваемым данным.
2. Заполнить вектора IOV ссылками на них.
3. Применить функцию
Отметим, что если данные начинаются не непосредственно с начала блока кэша (или другой структуры данных), то в этом нет никакой проблемы. Просто сместите первый вектор IOV на точку начала данных и соответственно откорректируйте поле размера.
Все функции обмена сообщениями, кроме функций семейства
Семейство
В нижеприведенной таблице сведены данные о вариантах функций семейства
Функция | Буфер передачи | Буфер приема |
---|---|---|
линейный | линейный | |
линейный | линейный | |
линейный | IOV | |
линейный | IOV | |
IOV | линейный | |
IOV | линейный | |
IOV | IOV | |
IOV | IOV |
Под линейным буфером я подразумеваю, что передается единый буфер типа void*
вместе с его длиной. Это легко запомнить: суффикс «v» означает «вектор», и он находится на том же самом месте, что и соответствующий параметр — первым или вторым, в зависимости от того, какой буфер — передачи или приема — объявляется векторным.