Timers in Lisp

Our first example demonstrates the use of timers in Lisp. Timers allow us to execute code at a specific point in the future or repeatedly at some interval. Let’s look at how to use timers.

(defpackage :timers
  (:use :cl))

(in-package :timers)

(defun main ()
  ;; Timers represent a single event in the future. We set up a timer
  ;; that will "fire" after 2 seconds.
  (let ((timer1 (sb-ext:make-timer 
                  (lambda () 
                    (format t "Timer 1 fired~%"))
                  :name "Timer 1")))
    (sb-ext:schedule-timer timer1 2)
    
    ;; We wait for the timer to fire. In a real application, you might do
    ;; other work here instead of just waiting.
    (sleep 2)
    
    ;; Now let's demonstrate how to cancel a timer before it fires.
    (let ((timer2 (sb-ext:make-timer 
                    (lambda () 
                      (format t "Timer 2 fired~%"))
                    :name "Timer 2")))
      (sb-ext:schedule-timer timer2 1)
      
      ;; We immediately try to unschedule (cancel) the timer.
      (if (sb-ext:unschedule-timer timer2)
          (format t "Timer 2 stopped~%")
          (format t "Failed to stop Timer 2~%"))
      
      ;; We wait for 2 seconds to show that Timer 2 doesn't fire.
      (sleep 2))))

(main)

In this Lisp example:

  1. We use the sb-ext:make-timer function to create timers. This is specific to SBCL (Steel Bank Common Lisp), one of the popular Common Lisp implementations.

  2. The first timer is scheduled to fire after 2 seconds. We use sleep to wait for it to fire.

  3. For the second timer, we schedule it and then immediately try to unschedule (cancel) it using sb-ext:unschedule-timer.

  4. We use sleep again at the end to give the second timer time to fire (if it was going to), demonstrating that it has indeed been cancelled.

To run this program:

$ sbcl --script timers.lisp
Timer 1 fired
Timer 2 stopped

The output shows that the first timer fired after approximately 2 seconds, while the second timer was successfully stopped before it had a chance to fire.

Note that the exact timing might not be precise due to system scheduling and other factors. In a real-world application, you might want to use more sophisticated synchronization mechanisms depending on your specific requirements.