Обычное чтение из 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)
).