2014年5月25日日曜日

Common Lisp のスレッド処理


このエントリーをはてなブックマークに追加


Common Lispにおけるスレッド処理は処理系依存であり、利用する場合はなかなか悩ましい問題です。そんな頭痛の種を解決してくれる一つの手段として、bordeaux-threads というライブラリがあります。

bordeaux-threads は処理系依存のスレッド処理をラップして、共通の記述が可能となる事を目的として開発されたライブラリです。bordeaux-threads は QuickLisp から導入可能です。
(ql:quickload :bordeaux-threads)

利用イメージは以下となります。


(require :bordeaux-threads)

(defpackage :threads-test-pkg
  (:use :cl
        :bordeaux-threads))

(in-package :threads-test-pkg)

(progn
  (format t "# start thread test~%")

  (let* ((test-counter #'(lambda (thread-identifier-num count interval)
                           (let ((*standard-output* #.*standard-output*))
                             (format t "## start-thread: ~s~%" thread-identifier-num)
                             (dotimes (i count)
                               (sleep interval)
                               (format t "### thread ~s --- ~s~%" thread-identifier-num i))
                             (format t "## end-thread: ~s~%" thread-identifier-num))))
         (test-thread-alive-p #'(lambda (thread)
                                  (let ((*standard-output* #.*standard-output*))
                                    (format t "~a: ~a~%" (thread-name thread) (thread-alive-p thread)))))

         ;; スレッドの生成と開始
         (thd1 (make-thread #'(lambda ()
                                (funcall test-counter 1 5 3))
                            :name "thread 1"))
         (thd2 (make-thread #'(lambda ()
                                (funcall test-counter 2 5 2))
                            :name "thread 2"))
         (thd3 (make-thread #'(lambda ()
                                (funcall test-counter 3 5 1))
                            :name "thread 3")))

    ;; スレッドの状態
    (funcall test-thread-alive-p thd1)
    (funcall test-thread-alive-p thd2)
    (funcall test-thread-alive-p thd3)

    ;; スレッドの終了を待つ
    (join-thread thd1)
    (join-thread thd2)
    (join-thread thd3)

    ;; スレッドの状態
    (funcall test-thread-alive-p thd1)
    (funcall test-thread-alive-p thd2)
    (funcall test-thread-alive-p thd3))

  (format t "# end thread test~%"))

基本的な考え方は、 make-thread で関数を引数にしてスレッドを生成し、join-thread でその終了を待つ、という記述になります。

実行結果
=>
# start thread test
## start-thread: 1
## start-thread: 2
## start-thread: 3
thread 1: T
thread 2: T
thread 3: T
### thread 3 --- 0
### thread 2 --- 0
### thread 3 --- 1
### thread 1 --- 0
### thread 3 --- 2
### thread 2 --- 1
### thread 3 --- 3
### thread 3 --- 4
## end-thread: 3
### thread 1 --- 1
### thread 2 --- 2
### thread 2 --- 3
### thread 1 --- 2
### thread 2 --- 4
## end-thread: 2
### thread 1 --- 3
### thread 1 --- 4
## end-thread: 1
thread 1: NIL
thread 2: NIL
thread 3: NIL
# end thread test
NIL

APIドキュメントはこちらから参照できます。
http://trac.common-lisp.net/bordeaux-threads/wiki/ApiDocumentation

0 件のコメント:

コメントを投稿