遠藤です。

2012/06/26 SASADA Koichi <ko1 / atdot.net>:
>>>  begin
>>> >    # 何か処理
>>> >  ensure
>>> >    Thread.mask_interrupt(Exception, :uninterruptible) do
>>> >      # 一度全部割り込み禁止にして
>>> >      Thread.mask_interrupt(SignalException, :blocking_interruptible)
>>> > do
>>> >        # シグナルだけ割り込みを許して
>>> >        # リソース解放処理
>>> >      end
>>> >    end
>>> >  end
>> 外側が :immediate_interruptible であるとすると、これは race がありますよね。
>>
>> 「何か処理」で例外が起きて、ensure 節に入った後、
>> Thread.mask_interrupt(Exception, :uninterruptible) を呼び出す前に
>> 非同期イベントによる例外が起きると、リソース開放処理がスキップされます。
>>
>> 実装上はそこでは例外は起きないのかもしれませんが...
>
>  確かに,仰るとおりです.寝ぼけた頭では,とりあえず
>
> (1) 「実装上はそこでは例外は起きない」ことを仕様にする
> (2) ensure に細工する(あまりやりたくない)
> (3) 利用者が immediate にしない
>
> が考えられると思います.どれがいいでしょう.または,他の選択肢はあるで
> しょうか.


以下のようにすれば現状の API で問題ないと思うのですが、
何か見落としているでしょうか。

  # (1) と (2) の間の割り込みを防ぐために
  Thread.mask_interrupt(Exception, :blocking_interruptible) do # (0)
    begin
      # begin 〜 ensure 内での割り込みはいつでも許す
      Thread.mask_interrupt(Exception, :immediate_interruptible) do
        # 何か処理
      end
    ensure # (1)
      # (0) のおかげでこの間に割り込まれることはない
      Thread.mask_interrupt(Exception, :uninterruptible) do (2)
        # 一度全部割り込み禁止にして
        Thread.mask_interrupt(SignalException, :blocking_interruptible) do
          # シグナルだけ割り込みを許して
          # リソース解放処理
        end
      end
    end
  end

-- 
Yusuke Endoh <mame / tsg.ne.jp>