Home

missionary.core/sem

Usage

Description

A port constructor defining a semaphore. A semaphore maintains a set of permits which can be acquired and released. Acquisition is an asynchronous effect completing with nil when the permit is made available.

Note : holding is a simple wrapper around ? and try/finally that can be used to make sure every acquired permit is eventually released.

Examples

Dining philosophers with forks represented as binary semaphores and philosophers as sp blocks. This is the resource hierarchy solution, nested semaphores are acquired in a consistent order to prevent deadlocks.

(require '[missionary.core :as m])

(defn phil [id f1 f2]
  (m/sp
    (loop []
      (prn id :thinking)
      (m/? (m/sleep 50))
      (m/holding f1
        (m/holding f2
          (prn id :eating)
          (m/? (m/sleep 70))))
      (recur))))

(def forks (vec (repeatedly 5 m/sem)))

(def dinner
  (m/join (constantly nil)
    (phil 'descartes (forks 0) (forks 1))
    (phil 'hume      (forks 1) (forks 2))
    (phil 'plato     (forks 2) (forks 3))
    (phil 'nietzsche (forks 3) (forks 4))
    (phil 'kant      (forks 0) (forks 4))))

(def main (m/timeout dinner 300))

(def ps (main #(prn :success %) #(prn :failure %)))
descartes :thinking
hume :thinking
plato :thinking
nietzsche :thinking
kant :thinking
descartes :eating
plato :eating
kant :eating
descartes :thinking
hume :eating
plato :thinking
hume :thinking
nietzsche :eating
descartes :eating
kant :thinking
descartes :thinking
kant :eating
plato :eating
nietzsche :thinking
:success nil

Synchronicity

See also