2010年5月6日1:24 Yusuke Endoh <redmine / ruby-lang.org>:

> 2 について、現状は Thread#raise には以下のような race が存在します。
>
>  t1: begin 節を実行している
>  t2: t1.raise する
>  t1: rescue/ensure 節の実行を開始する
>  t3: t1.raise する
>  t1: rescue/ensure 節が実行されないまま再度例外が発生する

> これを、Thread#raise の前に Mutex#lock するというルールにすれば、
> race を避けて使うことができるようになります。と思います。

なにか後始末が必要な処理があるとします。
たとえば、open したものは close しないといけないとして、
以下のコードを考えます。

  begin
    f = open(filename)
  ensure
    f.close
  end

ここで、open が終了した後、f に代入する前にコンテキストスイッチが起こると
どうでしょうか。
コンテキストスイッチの結果、他のスレッドが動いて、上記のコードを動かしている
スレッドを raise したとします。

そうすると、ensure 節が実行されるわけですが、close はできません。
なんでかというと、open で生成した IO オブジェクトがどこにも
記録されていないからです。

これは上記の Mutex#lock を使っても防げません。
一回しか Thread#raise していないからです。

というわけで、rescue/ensure 節の中で他から raise されるのをどうにかすれば
Thread#raise が安全になる、というわけではありません。

> # ちなみにこの race はシグナルにも存在します

POSIX シグナルでは、受け付けたシグナルは signal handler 内でマスクされるので、
handler 内で再度そのシグナルで割り込まれる、という心配はありません。

昔話としてはそうではなかったものもあったようで、その race の話は
検索すれば出てくるかもしれません。
-- 
[田中 哲][たなか あきら][Tanaka Akira]