Обычное чтение из FIFO с тайм-аутом

У меня есть такой код

(let ((file (open cur-fifo :if-does-not-exist :create)))
  (format t "~A~%" (read-line file nil))
  (close file))

Который, насколько я могу судить, работает нормально, за исключением того, что он будет блокироваться на неопределенный срок, если в cur-fifo не было записано никаких данных. Я хочу, чтобы время ожидания истекло и я вернул NIL, если данные не могут быть прочитаны в течение ~0,1 секунды или около того.

Работает на SBCL 1.1.18, на 64-битном Gentoo Linux

1 ответ

Решение

Модель FIFO

Когда ты open fifo специальное устройство (для чтения), блоки системного вызова, если только

  • fifo уже открыт (другим) процессом для записи ИЛИ
  • Вы передаете O_ASYNC в open(2) - что вы, возможно, не сможете сделать в своей реализации, если не используете пакет низкого уровня sb-posix

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

Common Lisp

То, что вы ищете, это listen (смотрите также with-open-file):

(with-open-file (fifo "my-fifo" :if-does-not-exist :create)
  (when (or (listen fifo)
            (progn (sleep 0.1)
                   (listen fifo)))
    (format t "Read [~A]~%" (read-line fifo))))

отладка

Обратите внимание, что специальная обработка устройства не обязательно одинаково хорошо поддерживается всеми поставщиками CL. Если вышеперечисленное не работает, выполните несколько экспериментов с REPL: откройте fifo, Смотри что listen возвращается, напишите что-нибудь там, посмотрите, что listen отчеты сейчас, &c.

Если listen все еще возвращается nil даже если вы уже что-то записали в канал, это может означать, что ваш CL не распознает файл как специальное устройство. Возможно, вам придется передать некоторые специфические для реализации аргументы open например, :buffering nil или что-то (попробуйте (describe 'open)).

Другие вопросы по тегам