Skip to content

Part III: マルチタスキングとスケジューリング

概要

本章では、Clojure の atom とイベント同期を学びます。


Atom(アトム)

;; 作成
(def counter (atom 0))

;; 更新
(swap! counter inc)        ;; 関数適用
(swap! counter + 10)       ;; 引数付き
(reset! counter 0)         ;; 直接設定

;; 取得
@counter  ;; または (deref counter)

イベント同期

イベントオブジェクト

(defn create-event
  "イベントオブジェクトを作成"
  []
  {:ready (atom false)
   :lock (Object.)})

(defn signal-event!
  "イベントをシグナル"
  [event]
  (locking (:lock event)
    (reset! (:ready event) true)
    (.notifyAll (:lock event))))

(defn wait-event!
  "イベントを待機"
  [event]
  (locking (:lock event)
    (while (not @(:ready event))
      (.wait (:lock event)))
    (reset! (:ready event) false)))

GameLoop 実装

ゲーム状態

(defn create-game-state
  "ゲーム状態を作成"
  []
  {:event-count (atom 0)
   :rendered-count (atom 0)
   :running (atom true)})

(defn process-event! [state]
  (swap! (:event-count state) inc))

(defn render-frame! [state]
  (swap! (:rendered-count state) inc))

ゲームループ

(defn run-game-loop!
  "ゲームループを実行"
  [state iterations]
  (let [processor-event (create-event)
        renderer-event (create-event)]
    ;; イベント処理スレッド
    (future
      (dotimes [_ iterations]
        (wait-event! processor-event)
        (process-event! state)
        (signal-event! renderer-event)))
    ;; レンダリングスレッド
    (future
      (dotimes [_ iterations]
        (signal-event! processor-event)
        (wait-event! renderer-event)
        (render-frame! state)))))

atom vs ref

特徴 atom ref
用途 単一値 複数値の協調更新
更新 swap!, reset! alter, ref-set
トランザクション 不要 dosync 必須

次のステップ

Part IV では、Fork/Join と Pipeline パターンを学びます。