git clone ''

(ql:quickload :trivial-channels)


This is a very, very trivial implementation of channels (and a queue). I find myself using it in a few places where very trivial message passing is needed and a more complex, robust solution would be overkill.

(let ((channel (make-channel)))
  (sendmsg channel 'anything)
  (recvmsg channel)) ;; => ANYTHING


Notably, recvmsg supports a timeout. These functions properly lock and it's safe to share a channel between threads (that being the entire purpose).


While trivial-channels should be simple enough you can adapt it to many usage patterns, for simple bi-directional message passing I have found it easiest to simply pass a message with a return-channel included:

;;; Sender:
(defvar *global-listener* (make-channel))
(defvar *done* nil)

(let* ((return-channel (make-channel))
       (msg (cons 'value return-channel)))
  (sendmsg *global-listener* msg)
  (recvmsg return-channel))

;;; Meanwhile, in another thread:
(loop until *done* do
  (let ((msg (recvmsg *global-listener*)))
    (let ((value (car msg))
          (channel (cdr msg)))
      ;; insert useful things here
      (sendmsg channel ...))))

Of course, you needn't create a new return channel every time, either, if you are worried about consing, but this is an easy way to pass functions to a specific thread, implement actors, etc.


The queue used to implement this is also available via the package :trivial-channels.queue, since it's sometimes handy to have a trivial queue, too.

Queues do not lock.

Queues are implemented with conses.

All add or remove type operations return the item (or cons) being handled, unless otherwise noted.