| 公式ページ | http://www.sbcl.org/ |
| 最新バージョン | 1.0.16 |
SBCL はオープンソース(フリーソフトウェア)な ANSI Common Lisp のコンパ イラとランタイムです.ネイティブコンパイラ,デバッガ,その他の拡張が統 合された対話的環境を提供します.
SBCL は多くのプラットフォーム上で動作します.現在サポートされているプラッ トフォームやどのように新しいプラットフォームに SBCL を移植するかについ てより詳細な情報については プラットフォームサポートページ を参照して ください.
SBCL の最新バージョンは 2007/6/26 にリリースされた 1.0.7 です.リリース ノートは ニュース ページで参照できます. お使いのプラットフォーム向 けの SBCL 配布物をダウンロードするには SBCL の入手方法 ページを御覧 ください.
SBCL の TeXInfo 形式のマニュアルは現在執筆中です.最新の TeXInfo ソース はソースコードに含まれている doc/manual ディレクトリに含まれています.
内部実装についての詳細に興味のある人は SBCL Internals という CLiki から読んでゆくと良いでしょう.0.9.9 から Win32 対応パッチのマージが開始 されたので,今後は Windows でも SBCL が使えるようになるのかもしれません ね.現在でも SBCL のビルド程度は可能ですが,添付のモジュール等の対応具 合もあり趣味人以外が使える段階ではないです.
0.9.17 から、MSI 形式のインストーラが用意されて、インストールが楽になり つつあります。まぁ、Win32 上ではスレッドも使えないうえ、 Win32 サポート はほとんどないので、CLISP に比べてあまりメリットがありませんが、一応 SLIME 環境も構築できています。イメージのサイズが大きすぎて未だに PHS 回 線しかない私には配布できません。
http://prdownloads.sourceforge.net/sbcl/sbcl-0.9.17-x86-windows-binary.msi?download
*BREAK-ON-SIGNALS* の束縛する値が型指定子でなくてももはや無限再帰が生じないようになりました
--noinform が渡された場合と同じ動作です。(thanks to Kevin Reid)
関連設定ファイルあれこれ.環境は Gentoo Linux + SBCL CVS 版 9.17. です.
.emacs の SBCL 固有部分 – .emacs
(defun sbcl-start () (interactive) (shell-command "sbcl --core /home/onjo/local/lib/sbcl/main.core --load /home/onjo/.slime.lisp &"))
SLIME 用設定ファイル – .slime.lisp
#+sbcl (setq sb-impl::*default-external-format* :utf-8) (setq swank::*coding-system* "utf-8-unix") (swank:create-server :port 4005 :dont-close t))
作業用イメージ作成シェルスクリプト – make-sbcl-image
#!/bin/sh
LANG=C sbcl --noinform --no-print <<EOT
(eval-when (:load-toplevel :execute)
(require :asdf)
(require :asdf-install)
(require :sb-rotate-byte)
(require :sb-md5)
(require :sb-posix)
(require :sb-rt)
(require :sb-simple-streams)
(require :sb-bsd-sockets)
;; (require :sb-aclrepl)
)
(pushnew
(merge-pathnames "lisp/asd/" (user-homedir-pathname))
asdf::*central-registry*)
(asdf:oos 'asdf:load-op :cl-fad)
(asdf:oos 'asdf:load-op :cl-interpol)
(asdf:oos 'asdf:load-op :cl-ppcre)
(asdf:oos 'asdf:load-op :cl-who)
(asdf:oos 'asdf:load-op :html-template)
(asdf:oos 'asdf:load-op :iterate)
(asdf:oos 'asdf:load-op :unification)
(asdf:oos 'asdf:load-op :cl-dot)
#-sbcl (asdf:oos 'asdf:load-op :md5)
(asdf:oos 'asdf:load-op :xmls)
(asdf:oos 'asdf:load-op :s-xml)
(asdf:oos 'asdf:load-op :s-xml-rpc)
(asdf:oos 'asdf:load-op :cffi)
(asdf:oos 'asdf:load-op :cffi-uffi-compat)
(asdf:oos 'asdf:load-op :yacc)
(asdf:oos 'asdf:load-op :kmrcl)
(asdf:oos 'asdf:load-op :cl-plus)
(asdf:oos 'asdf:load-op :cl-utilities)
(asdf:oos 'asdf:load-op :json)
(asdf:oos 'asdf:load-op :fiveam)
(asdf:oos 'asdf:load-op :screamer)
(asdf:oos 'asdf:load-op :log4cl)
(asdf:oos 'asdf:load-op :series)
(asdf:oos 'asdf:load-op :ironclad)
(asdf:oos 'asdf:load-op :swank)
#+nil
(progn
(asdf:oos 'asdf:load-op :uffi)
(asdf:oos 'asdf:load-op :clsql)
(asdf:oos 'asdf:load-op :clsql-uffi)
(asdf:oos 'asdf:load-op :clsql-sqlite3)
(asdf:oos 'asdf:load-op :curl)
(asdf:oos 'asdf:load-op :puri)
(asdf:oos 'asdf:load-op :acl-compat)
(asdf:oos 'asdf:load-op :htmlgen)
(asdf:oos 'asdf:load-op :aserve)
(asdf:oos 'asdf:load-op :webactions))
(asdf:oos 'asdf:load-op :lw-compat)
(asdf:oos 'asdf:load-op :closer-mop)
(asdf:oos 'asdf:load-op :contextl)
(asdf:oos 'asdf:load-op :cldoc)
(asdf:oos 'asdf:load-op :html-encode)
(asdf:oos 'asdf:load-op :colorize)
(asdf:oos 'asdf:load-op :cxml)
;; #+clisp (asdf:oos 'asdf:load-op :clisp-sqlite)
(asdf:oos 'asdf:load-op :rt)
(asdf:oos 'asdf:load-op :clsql)
(asdf:oos 'asdf:load-op :clsql-uffi)
(clsql-sys::push-library-path #p"/usr/lib/")
(asdf:oos 'asdf:load-op :clsql-sqlite3)
(asdf:oos 'asdf:load-op :iso8601-date)
(asdf:oos 'asdf:load-op :local-time)
(asdf:oos 'asdf:load-op :cl-store)
(asdf:oos 'asdf:load-op :cl-prevalence)
;;(load (merge-pathnames "lisp/unstable/lisa/install.lisp" (user-homedir-pathname)))
;; (asdf:oos 'asdf:load-op :lisa)
(load (merge-pathnames "lisp/lib/common/XML/Load-XMLisp.lisp" (user-homedir-pathname)))
(loop repeat 10 do (gc :full t))
(let ((core (merge-pathnames "main.core"
(or (sb-posix:getenv "SBCL_HOME") "./"))))
(save-lisp-and-die core :purify t))
(exit)
EOT
1.0.1 から入った新しい XREF 機能は、SLIME のサポートも同時に入ったため便利です。なので関連ドキュメントの翻訳。
Juho Snellman's Webblog (http://jsnell.iki.fi/blog/archive/2006-12-05-sbcl-xref.html) の翻訳
SBCL は 1.0.0.18 から正式な xref 実装を備えるようになりました。これは「この関数はどこから呼び出されているのか?」というような質問への答えを 与えてくれます。これは M-x slime-list-callers で使われているヒープを調べる方法(これ自体はとても賢いやり方だと思います)よりも、さらに 便利なものです。xref では SLIME のアプローチと比較して以下の利点が得られるように設計しました。
いくつかの場合では xref の情報は保存されません。経験則に従うなら、 defun と defmethod が同じレベルにあるなら、xref は動作するでしょう。 そうでなければ動作しないでしょう。後者の実例は次のような場合です。
(defmacro def-foo (...) ...) (def-foo ...)
(defvar *a* (lambda () (bar)))
(defclass () ((a :initform (bar))))
(defun foo ()
(macrolet ((bar ()
(baz)))
(bar)))
それらや、類似した個所の xref 情報を記録する方法のためのアイデアはいくつかありますが、まだ詳細な仕事はできていません。 もし、上の例以外の状況で、 xref が期待通りに動作しない場所を見つけたなら、是非教えてください。
新しい xref を使うには、 CVS 版の SLIME で、通常の Slime のクロスリファレンス用コマンド を使用してください。 xref のための作業(と、blog には書いていませんでしたが、いくつかの SBCL の改良のための作業)に出資してくれた ITA Software に感謝します。
SLIME のクロスリファレンス用コマンドは、多種多様な Lisp システム毎にサ ポートされている機能に基づいています。組み込みの XREF サポートのない処 理系に対しては、SLIME はポータブルな XREF パッケージ(これは、CMU AI Repository からもってきて、SLIME に同梱されています)を使って問い合わせを行います。
それぞれのコマンドは、ポイント位置のシンボルに対して動作します。シンボルが なければ、プロンプトを表示します。プリフィックス引数を使うと、必ずプロンプトを 表示するようになります。
C-c C-w c slime-who-calls 呼び出し元の関数を表示します
C-c C-w r slime-who-references グローバル変数への参照を表示します
C-c C-w b slime-who-binds グローバル変数の束縛を表示します
C-c C-w s slime-who-sets グローバル変数への値の設定を表示します
C-c C-w m slime-who-macroexpands マクロ展開個所を表示します
M-x slime-who-specializes あるクラスに特定化されるすべてのメソッドを表示します
また、 呼び出し元/呼び出し先表示 コマンドもあります。これらの操作は、関数オブジェクトを通じて下位のヒープからコールグラフを探索します。 これらは、いくつかの Lisp 処理系でのみ利用可能で、詳細な XREF 情報が利用不可能な場合なもっとも役に立つ代用品です。
C-c < slime-list-callers 呼び出し元 (caller) 関数を表示します
C-c > slime-list-callees 呼び出し先 (callee) 関数を表示します
http://www.sbcl.org/manual/Efficiency.html や http://www.sbcl.org/manual/Threading.html の翻訳
後で修正する: CMUCL の良い性能を得るための章の内容をレビューして, Texinfo で再フォーマットして SBCL 向けにちょっと改変しては挿入しましょ う.それまでの間,オリジナルの CMUCL マニュアルの内容は 95% 以上 SBCL バージョンの Python コンパイラ (訳注: CMUCL, SBCL のネイティブコードコ ンパイラの名前が Python といいます) にも適用できます.次の章を参照してください.
CMUCL マニュアルのこれらの情報に加えて,いくつかの事を心にとめておいてください.
最後に Common Lisp は多くの部分を次のフレーズで表す事ができます. ="効率的にコンパイルすることができます.十分に賢いコンパイラなら."= このフレーズはあまり有名ではありません.なぜなら全ての最適化を可能にす るほど賢いコンパイラを実際に作る事は現在のコンパイラ技術を上回る仕事だ からです.かわりに,場合に応じたコードを手書きする事による最適化や,あ るいは対応する手書きの最適化がない場合には全く最適化を行わないという事 になります.SBCL 0.6.3 で最適化されないケースをいつくか示します.
(reduce #'f x) は,x の型がコンパイル時に判明していても最適化されません
(position 0 some-bit-vector) のようなビットベクタ操作
(remove item list :count 1) 特定のシーケンスに対するイディオム
(locally (declare (safety 1)) (assoc item list)) のような局所コンパ
イルポリシーが型チェックを要求しないケース.(現在では assoc するため
に内部的に endp のチェックが行なわれます)
もしあなたのシステムの性能が,「効率的にコンパイルできる構成要素から成っ ているのにおそい」というケースに遭遇したら,SBCL コンパイラはそれを効率 的にコンパイルする事ができないという事です.コンパイラへのパッチを書い てそれを送ってください.直接対象となるようなコードは十分直接的に書く事 ができます; ソース注の "deftransform" という文字列を検索してみてくださ い.沢山のサンプルがみつかるはずです.
SBCL はスタック上へのメモリアロケーションについて限定的なサポートを提供 しています.dynamic-extent 宣言は検証されません.コンパイラは無条件に信 頼されます.もし,Common Lisp 標準の制約に違反すると,うまくいくとプロ グラムはごみの値を持つだけですが,大抵の場合はシステムがクラッシュします.
この結果,大抵のスタックアロケーションは厳しい条件の元に行なわれる事に なります.speed や space の最適化値はその時点の safety や debug のより も高くなければなりません.たとえば
(locally
(declare (optimize speed (safety 1) (debug 1)))
(defun foo (&rest rest)
(declare (dynamic-extent rest))
(length rest)))
これは &rest リストはスタック上に確保されますが,次のコードではスタック 上に確保されないという事になります.
(defun foo (&rest rest) (declare (optimize speed (safety 1) (debug 1))) (declare (dynamic-extent rest)) (length rest))
なぜならば,こちらも &rest リストをアロケーションしますが,その変数の束 縛は最適化宣言のスコープの外側にあるからです.
多くの場合,dynamic-extent 宣言は有効です.たとえば SBCL は次のケースの 最適化を実装しています.
(let ((list (list 1 2 3))) (declare (dynamic-extent list) ...))あるいは
(flet ((f (x)
(declare (dynamic-extent x))
...))
...
(f (list 1 2 3))
...)
スタック領域には上限があることに注意すべきである.巨大なベクタをスタッ ク上に確保すると,スタックオーバーフローを発生させたり,SBCL プロセスが 以上終了する原因となる.
以下のようなものが計画されています.
いくつかの算術関数はある特性 – N 以下のビットの演算結果が N ビット以下
になる – を持っています.もしコンパイラがこのような式 (logand, exp,
mask) を発見したらそれらの式の関数ツリーやマスク結果の型は,=w= をビッ
ト幅とすると (unsigned-byte w) 以下になることや,すべての中間結果が
w ビットに切り詰められる,といった事がわかります.これによって,単
純な機械語コードを生成する事ができます.
次の例を見てみましょう.
(defun i (x y) (declare (type (unsigned-byte 32) x y)) (ldb (byte 32 0) (logxor x (lognot y))))
(lognot y) の結果は負で,かつ (signed-byte 33) という型になるか
もしれません.これは 32 bit プラットフォーム上ではネイティブな 32-bit
演算で扱うことができません.しかし, modular arithmetic 最適化はこれを
可能にします.なぜなら結果が 32 bit に切り詰められるため,コンパイラは
logxor や lognot を 32 bit の結果へと切り詰めるバージョンで置き替え,あ
らに変数 x, y の型も (unsigned-byte 32) であるため 32bit 演算か利用
できるようになります.
SBCL 0.8.5 からは +, -, logand, logior, logxor, lognot とその組み合わせ,
第二引数が正の ash,などの関数が対象となっています. 良いビット幅
は HPPA, MIPS, PPC, Sparc, x86 では 32 bit, Alpha では 64 bit です.よ
り小さな bit 幅のサポートも可能ではありますが,現在は実装されていません.
SBCL はホストオペレーティングシステムのスレッドもしくは軽量プロセスにマッ プした低レベルのスレッドインターフェースをサポートします.これはマシン に一つ以上の CPU がある場合,スレッドがハードウェアマルチプロセシングの 恩恵を受けられるという事を意味します.しかし,Lisp からスケジューラを制 御する事はできません.これらの機能は SB-THREAD パッケージで提供されます.
この機能を使用するには x86/x86-64 かつ Linux カーネル 2.6 で NPTL が有 効になったシステムが必要です.
(make-thread (lambda () (write-line "Hello, world")))
Structure: sb-thread:thread
Class precedence list: thread, structure-object, t
.. Thread type. Do not rely on threads being structs as it may change in future versions.
スレッド型です.スレッドが依存している構造は将来のバージョンで変更になる可能性があります.
Variable: sb-thread:*current-thread*
.. Bound in each thread to the thread itself.
全てのスレッドにおいて,実行中のスレッド自身に束縛されます.
Function: sb-thread:make-thread function &key name
.. Create a new thread of name that runs function. When the function returns the thread exits.
function で指定した関数と name で指定した名前を元に新しいスレッドを作成します.
関数がリターンするとスレッドが終了します.
Function: sb-thread:thread-alive-p thread
.. Check if thread is running.
スレッドが生存しているかどうかをチェックします.
Function: sb-thread:list-all-threads
.. Return a list of the live threads.
現在生存しているスレッドのリストを返します.
Condition: sb-thread:interrupt-thread-error
Class precedence list: interrupt-thread-error, error, serious-condition, condition, t
.. Interrupting thread failed.
スレッドでの割り込みエラーです.
Function: sb-thread:interrupt-thread-error-thread condition
.. The thread that was not interrupted.
スレッドは割り込まれません.
Function: sb-thread:interrupt-thread thread function
.. Interrupt the live thread and make it run function. A moderate degree of care is expected for use of interrupt-thread, due to its nature: if you interrupt a thread that was holding important locks then do something that turns out to need those locks, you probably won't like the effect.
生存しているスレッドに割り込んで,関数を実行します.そこで行なう変更 の加減は,割り込まれるスレッドの使用で予想される範囲に留めるべきです. もし割り込んだスレッドが重要なロックを保持しており,そのロックを必要 となるなにかを実行しようとすると望みの効果は得られないでしょう.
Function: sb-thread:terminate-thread thread
.. Terminate the thread identified by thread, by causing it to run sb-ext:quit - the usual cleanup forms will be evaluated
thread で指定されるスレッドを終了します.=sb-ext:quit= によって終了され,クリーンナップフォームが評価されます.
複数スレッドによるスペシャル変数の取り扱いは,他の実装と非常に似た挙動 で,大抵予想したとおりに動きます.
グローバルなスペシャル変数はすべてのスレッドで見えます.バインドされた値(例えば LET を使った場合など)はスレッドローカルになります.スレッドは 親のスレッドからダイナミックバインディングを継承しません.つまり
(defparameter *x* 0) (let ((*x* 1)) (sb-thread:make-thread (lambda () (print *x*))))
は 1 ではなく 0 を表示します.
Mutex は共有リソースのアクセスコントールに使われます.一つのスレッドが
ミューテックスを保持すると,他のスレッドはそれが解放されるまで待つ事に
なります.起こされるまで,スレッドは sleep します.
ミューテックスの要求にタイムアウトはありません.しかし,ウエイトを使い
たい場合には WITH-TIMEOUT マクロ(これは,N 秒後に TIMEOUT コン
ディションを通知します)を使う事ができます.
(defpackage :demo (:use "CL" "SB-THREAD" "SB-EXT"))
(in-package :demo)
(defvar *a-mutex* (make-mutex :name "my lock"))
(defun thread-fn ()
(format t "Thread ~A running ~%" *current-thread*)
(with-mutex (*a-mutex*)
(format t "Thread ~A got the lock~%" *current-thread*)
(sleep (random 5)))
(format t "Thread ~A dropped lock, dying now~%" *current-thread*)))
(make-thread #'thread-fn)
(make-thread #'thread-fn)
Structure: sb-thread:mutex
Class precedence list: mutex, structure-object, t
Mutex 型です.
Function: sb-thread:make-mutex &key name value
Mutex を作成します.
Function: sb-thread:mutex-name instance
mutex の名前へのアクセサです. setf 可能です.
Function: sb-thread:mutex-value instance
mutex の値です.もし解放されている Free 状態ならば nil になります.
setf 可能です.
Function: sb-thread:get-mutex mutex &optional new-value wait-p
mutex を取得し,値が NIL ならば新しい値,もしくはデフォルト値を設
定します.もし wait-p に非 NIL が指定されており,かつ Mutex
が使用中であるあんらば,利用可能になるまで sleep します.
Function: sb-thread:release-mutex mutex
mutex の値を nil に設定し,解放します.この Mutex を待っていたスレッ
ドを起こします.
Macro: sb-thread:with-mutex (mutex &key value wait-p) &body body
body のダイナミックスコープで mutex を取得します. もし値が
nil ならば value で指定された値もしくはデフォルト値が設定されます.
wait-p に非 NIL が指定されており,かつ mutex が使用中であ
るなら,利用可能になるまで sleep します.
Macro: sb-thread:with-recursive-lock (mutex) &body body
body のダイナミックスコープで Mutex を取得します.同じ mutex
に対してスコープ内での再帰的なロックが成功します.値としてデフォルト
値を用いている同じ mutex に対する with-mutex と
with-recursive-lock を混ぜて使用する事が許可されています.
POSIX 状態変数の設計をベースにしていますが,それゆえ CL 的に無作法な名 前の衝突があります.状態変数をチェックし,それが新になるまでスリープす るといった使い型があるでしょう.例えば,共有されたキューに対して,書き 込みプロセスは「キューが空」である事をチェックし,一つもしくは複数の読 み出しプロセスが「キューが空でなくなった」時を知る必要があるとします. これはシンプルに聞こえますが,他のプロセスがあなたの予想していない時に 動くと驚くほど簡単にデッドロックします.
これは三つのコンポーネントで構成されます.
waitqueue のような)状態変数
特に気をつけるべき点は,
condition-wait を呼ぶ時に,Mutex を保持する必要があります.=condition-wait= はそれを待つ間 mutex を解放します.そして,何らかの理由で帰って くる前に再びそれを取得します.
condition-notify を呼ぶ場合にも mutex を保持している必要があります
condition-wait からプロセスが帰ってくるのにはいくつかの状況が考えられます. condition が true になっているという事は保証されません.したがって目的に応じてリソースが利用可能になっているかどうかをチェックする必要があります.
(defvar *buffer-queue* (make-waitqueue))
(defvar *buffer-lock* (make-mutex :name "buffer lock"))
(defvar *buffer* (list nil))
(defun reader ()
(with-mutex (*buffer-lock*)
(loop
(condition-wait *buffer-queue* *buffer-lock*)
(loop
(unless *buffer* (return))
(let ((head (car *buffer*)))
(setf *buffer* (cdr *buffer*))
(format t "reader ~A woke, read ~A~%"
*current-thread* head))))))
(defun writer ()
(loop
(sleep (random 5))
(with-mutex (*buffer-lock*)
(let ((el (intern
(string (code-char
(+ (char-code #\A) (random 26)))))))
(setf *buffer* (cons el *buffer*)))
(condition-notify *buffer-queue*))))
(make-thread #'writer)
(make-thread #'reader)
(make-thread #'reader)
Structure: sb-thread:waitqueue
Class precedence list: waitqueue, structure-object, t
Waitqueue 型です.
Function: sb-thread:make-waitqueue &key name
Waitqueue を作成します.
Function: sb-thread:waitqueue-name instance
Waitqueue の名前へのアクセサです. setf 可能です.
Function: sb-thread:condition-wait queue mutex
自動的に mutex が解放され,そして自分自身がキューに入れられます.
他のスレッドが condition-notify を用いて通知してくると,再び
mutex が取得され,そして呼び出し元にリターンします.
Function: sb-thread:condition-notify queue &optional n
キューで待っているスレッドに n を通知します.
Function: sb-thread:condition-broadcast queue
キューで待っている全てのスレッドに通知します.
もし,ユーザーが同じ Lisp イメージ上に複数のビュー(例えば,複数の端末
やウィンドウシステム,ネットワーク経由のアクセスなど)を持っているなら
ば,典型的にはそれぞれのビューに対してそれぞれのセッション (フォアグラ
ンド/バッググラウンド/ ストップ スレッドのコレクション) が割り当てられ
ます.新しいセッション作成したいスレッドは,
sb-thread:with-new-session を使うことで自分自身をカレントセッション
から決して新しいセッションを作成できます.
sb-thread:make-listener-thread も参照してください.
一つのセッションの中でのスレッド間の調整はユーザーが注意を払う必要があ
ります.スレッドは foreground , background , stopped の 3
つの状態のうちのいずれかの状態を取ります.もし background のプオセ
スが REPL のプロンプトを表示しようとしたり,デバッガに入ろうとすると,
そのプロセスは停止され,そして停止された旨のメッセージが表示されます.
ユーザーは必要に応じてそのようなスレッドにスイッチする必要があります.
もし background スレッドがデバッガに入るとそれが中断される前にバッ
クグランドに押し戻せるような選択がなされます.入力ストリームに対する調
整は, sb-thread::get-foreground (これはブロックします) や
sb-thread::release-foreground を呼ぶ事によって管理されます.
sb-ext:quit はカレントセッションの全てのスレッドを終了しますが,他
の稼働中のセッションを終了させる事はありません.
スレッドは pthread といくつかの Linux 特有の機能(futex など)を使って 実装されています.
x86 上では,スペシャル変数へのスレッドローカルな束縛は %fs セグメントレ ジスタがスレッド毎の記憶領域を指すという機能を用いて実現されています. これは,もしスレッド動作する事を前提とする,もしくは新にスレッドを作成 する外部コードとリンクし,そのスレッドライブラリが %fs を非互換な方法で 使用していると面白い結果を引き起こす事があります.x86-64 では r12 レジ スタが同様の役割を果します.
キューは sys_futex() システムコールが利用可能である事を要求します.
これが, NPTL が要求される理由です.実行時にこのシステムコールが利用可
能である事がテストされます.
ガベージコレクションは既存のコンサバティブ世代別 GC によって実施されま す.アロケーションは小さな領域(典型的には 8K)単位で実施され,すべての スレッドは自身のリージョンをもっています.しかし,リージョンが埋め尽さ れた時,アロケートしている間はロックが必要となります.ガベージコレクショ ンが必要になった時には全てのプロセスが停止します.これはシグナルを送る 事によって実現されています.これはシステムコールに対して割り込みをかけ て奇妙な振舞いを起こすかもしれません.ストリームインターフェースはシス テムコールを正しく再開できる事が要求されていると思いますが,他のブロッ キングな呼び出し(外部ライブラリコード)などについては考慮が必要です.
おおくの SBCL ライブラリはスレッドセーフである事が検証されていません.
コンパイルや fasl のロードなど並列化できない,いくつかの明らかにアンセー フな領域のものは大きくロックされています.これらの領域での作業は現在進 行中です.
新たに作成されたスレッドはデフォルトで同じ POSIX プロセスグループと作成
元スレッドと同じセッションに属します.これはキーボード割こ込みの取り扱
いに影響します.端末の intr キー (Control-C) を押すと,SBCL では通常
background となっている Lisp スレッドを含んだ同じフォアグラウンドプ
ロセスグループの全てのプロセスに割り込みがかかるからです.これが望まし
くない場合には,バックグラウンドスレッドは SIGINT シグナルを無視す
るように設定るう必要があります.
sb-thread:make-listener-thread は新しい POSIX セッションとなる
Lisp セッションを作成するために追加されました.これを使えば,あるウィン
ドウで Control-C を押しても,他の Listener に割り込みがかかる事はありま
せん.