POSIX именованный канал (fifo) удаляет запись в неблокирующем режиме - PullRequest
1 голос
/ 01 мая 2020

Я использую именованные каналы POSIX (fifos) для отправки записей из одного или нескольких потоков для чтения другим потоком (только один поток выполняет чтение). Однако 83-я запись из 100 записей просто отбрасывается. Ядро клиента вызывает запись, и возвращаемое значение правильно указывается как длина записи (720 байт), поэтому ядро ​​клиента (записывающего) подтверждает, что запись отправлена, но переключается на ядро ​​считывателя в режиме отладки gdb с блокировкой планировщика. затем я читаю несколько предыдущих записей, а затем не могу прочитать - в канале нет записей, хотя ядро ​​клиента (записывающего) подтвердило запись.

Емкость канала составляет 65 536 байт (по умолчанию в Linux). Я предполагаю, что содержимое канала уменьшается на 1 запись для каждого чтения записи, поэтому в момент, когда 83-я запись отбрасывается, у меня есть около 5 предыдущих записей в канале, или 3600 байт - недостаточно для заполнения канала.

Я открыл трубы в неблокирующем режиме, потому что, когда я открыл их в режиме блокировки, оба конца замерзли. Согласно справочным страницам в http://man7.org/linux/man-pages/man7/fifo.7.html, «FIFO должен быть открыт на обоих концах (чтение и запись), прежде чем данные могут быть переданы. Обычно, открытие блоков FIFO до открытия другого конца также. " Моя проблема заключается в том, что оба конца блока и не будет go дальше. В нем также говорится: «В Linux открытие FIFO для чтения и записи будет успешным как в режиме блокировки, так и в режиме неблокирования. POSIX оставляет это поведение неопределенным».

Код на каждом конце прост:

int64_t fifo_write(int fd, const void *buf, size_t count) {

    int status_write = write(fd, buf, count);

    return status_write; }

int64_t fifo_read(int fd, void *buf, size_t count) {

    int status_read = read(fd, buf, count); 

    return status_read; }

Функции C вызываются из моей программы NASM:

mov rdi,[fifo_read_fd]
lea rsi,[fifo_buffer]
mov rdx,720
call fifo_read wrt ..plt

mov rdi,[fifo_write_fd]
mov rsi,[rbp-24]
mov rdx,720 ; bytes
push r11
push rcx
call fifo_write wrt ..plt
pop rcx
pop r11

Мои вопросы:

  1. Что может вызвать удаление записи? Это не похоже на емкость канала, если канал не очищается при чтении каждой записи - даже все 83 записи будут занимать 59760 байт, что ниже пропускной способности канала 65 КБ в Linux. Это может быть связано с неблокирующим режимом, но если канал не заполнен, нет причин для блокировки.

  2. Как я могу открыть оба конца в режиме блокировки (учитывая, что оба конца зависают, каждый ждет другого), и есть ли у меня какие-либо проблемы с режимом блокировки?

  3. Я мог бы открыть оба конца в режиме чтения / записи, потому что мой код записывает только из одного или нескольких потоков на одном конце и читает из 1 потока (только) на другом конце. Хотя «POSIX оставляет это поведение неопределенным», есть ли причины не открывать оба конца в режиме чтения / записи в этой ситуации?

Я не разместил ни одного другого кода с этим вопросом (кроме как выше), потому что я только ищу идеи о лучшем способе решения проблемы пропущенной записи в случае Я описал.

1 Ответ

3 голосов
/ 01 мая 2020

У вас есть несколько устройств записи, использующих один FIFO для отправки сообщений размером 720 байт. POSIX требует только записи PIPE_BUF (обычно 512 байт), чтобы быть атомами c. Это означает, что более длинные записи могут чередоваться с записями из других потоков и повреждаться.

Независимо от размера PIPE_BUF, каналы являются потоками, и у них нет понятия сообщения, а это означает, что вам нужно самостоятельно разделять сообщения, чего не делает ваш код. Другими словами, ваш код считывателя не может восстановить отдельные сообщения при наличии нескольких устройств записи.

Вместо этого вы можете использовать Unix датаграмма сокета . Каждое сообщение в сокете дейтаграммы Unix является сообщением атома c, и оно записывается и полностью читается в одном системном вызове (sendto и recvfrom).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...