Threadとtimeoutと後始末
# 閉じられないファイルの例 Thread.start { f = open('foo', 'w') if false raise x end f.close }
さて、このままスクリプトが終了するならいいんだけど、これが何度も繰り返されるとファイルがいつまでたっても閉じられないまま困ることになるかもしれない。ファイル以外にもデータベースとかSMTPとか、最後にcloseやdisconnectやfinishが必要なものって結構ある。
そんな時はensureを使えば大丈夫。
Thread.start { begin f = open('foo', 'w') if false raise x end ensure # 例外が投げられてもここは必ず実行される。 f.close if f end }
スレッドが途中で終了させられても大丈夫。
t = Thread.start { begin sleep 3 # 眠っている間に、 f = open('foo', 'w') if false raise x end ensure # こんな時でも必ず実行される。 f.close if f end } t.kill # 眠っている間に(ファイルを開く前に)スレッドを止めてしまう
この時はたぶんfがnilなので if f が効いてくる。
スレッド内のメソッドでファイルを開いたりしているときはメソッド内でensureすれば大丈夫。同じように正常終了だろうと例外だろうとスレッドが終わろうと必ずensureは実行されるので。
def foo_method f = open('foo', 'w') if false raise x end ensure f.close if f end Thread.start { foo_method() }
タイムアウトでも全く同じ
timeout(5) { begin sleep 10 puts '10秒寝る前にタイムアウトするから出力されない' ensure puts 'でもここはどんな時でも出力される' end }
タイムアウトはスレッドで実装されているので。