Search code examples
lispcommon-lispslime

Non-blocking input in lisp


I have program that runs for long periods of time and I'd like to interrupt it but not with ctrl-c ctrl-c. I also don't want the system to wait for a keystroke every so often. Instead, if I do press a key, I want it to wrap things up and exit. I found listen and read-char-no-hang but I can't get it to work right. Here's what I tried to do

(let ((f nil))
  (loop while (not f) do
     (if (listen)
       (setf f t)))))

Obviously, this is doing less than a sloth on Xanax as far as finding key=-presses. What am I doing wrong?


Solution

  • CCL has multithreading, I believe. You could try spawning a worker thread in the background and have a control thread doing a blocking read, and then communicating via a special variable. The following works in Lispworks, I don't have CCL available. You'd have to translate the mp:process-run-function to whatever CCL uses to spawn threads:

    (defparameter *f* nil)
    (defun cmd-loop ()
      (setf *f* nil)
      (mp:process-run-function "work" () #'do-work)  ; Spawn worker
      (read-char *terminal-io*)                      ; Blocking read
      (setf *f* t))
    (defun do-work ()
      (loop while (not *f*)
            do 
              (format t "~a " *f*)
              (finish-output)))
    (cmd-loop)
    

    The big assumption I'm making here is that CCL multithreading works similarily to LW multithreading, so that both threads can access the shared state variable *f*.