ささだです.

(2011/09/23 18:47), Shota Fukumori (sora_h) wrote:
> 元の問題がややこしくなっているので一旦まとめると,
> 
> a = Object.new
> mutex = Mutex.new # finalizer と共有している mutex
> 
> ObjectSpace.define_finalizer(a) { # (1) a に対する finalizer
>   mutex.synchronize { p "ho" }    # (2) ここでロックしようとするが, (3) と
>                                   # 同じスレッドなので ThreadError 例外発生
>                                   # (例外の発生は rescue で確認可能)
> }
> mutex.synchronize { # (3)
>   a = nil
>   GC.start
>   p "hi"
>   loop{ Object.new } # このループ中で (1) で定義した finalizer が呼ばれる
> }
> 
> このようなサンプルコードを実行したときに (3) の mutex.synchronize 中に
> オブジェクト a が解放された後,何らかのタイミングで a に対する finalizer
> (1) が実行されると, (3) で mutex がロックされたまま同じスレッド (?) で
> 再び (2) で Mutex#lock を試みるため ThreadError "dead lock; recursive
> locking" (thread.c:3555) が発生しています.
> 
> で,この問題に対する解決策は
> 
> 1. これは仕様という事にしてしまう
>    → これが採用された場合,Glass_saga の GC.disable と GC.enable を挟む
> パッチ
>    を取り込んで解決の方向?
> 2. その他何らかの良い方法

 問題のまとめをありがとうございます.

 ファイナライザの実行は,何時起こるかわからないものなので,デッドロック
の可能性がある処理を行うのは,プログラムが悪い,ということになります.基
本的には,デッドロックを起こさないように書き直す必要がありますが,例えば
上記の場合では,mutex.trylock を利用することで回避することができます.


# 本質的に,何かしら他の対処が必要な話だろうか?

-- 
// SASADA Koichi at atdot dot net