2012-01-27 11 views
5

私はソートのデータベースライブラリを作成しています。自動的にデータベースハンドルの寿命を管理非同期例外のネストされたマスキング

withDatabase :: FilePath -> (DBHandle -> IO a) -> IO a 

:それは輸出する基本的な機能は以下の通りです。

内部では、withDatabaseは、bracket機能を使用します.Control.Exception。私の特定の場合には

withDatabase path f = bracket (openDatabase path) closeDatabase f 

openDatabaseは、いくつかの重要なI/Oを実行するため、長い時間のためにブロックすることがあります。このため、非マスク例外を使用して非同期例外の一部を実行したいと考えています。

openDatabase :: FilePath -> IO DBHandle 
openDatabase path = mask $ \restore -> do 
         h <- openFile path ReadWriteMode 
         restore (doLongStuff h) `onException` (hClose h) 
         ... 
         return (DBHandle h) 

私は、このコードが意図する効果を生み出しているかどうかわかりません。

今回は、その定義とbracketを交換する、のはwithDatabaseを振り返ってみましょう:

withDatabase path f = mask $ \restore -> do 
    h <- openDatabase path 
    r <- restore (f h) `onException` closeDatabase h 
    _ <- closeDatabase h 
    return r 

実行中のある時点で、コールスタックは、次のようになります:

\- withDatabase 
\- mask 
    \- openDatabase 
    \- mask 
    \- restore 
    \- doLongStuff 

ドキュメントについてControl.Exceptionモジュールは、maskへのネストされた呼び出しについて何かを持っています:

maskへの引数に渡されるrestoreアクションは、必ずしも非同期例外のマスクを解除するとは限らず、マスキング状態を囲むコンテキストの状態に復元するだけであることに注意してください。したがって、非同期例外が既にマスクされている場合、マスクを使用して例外のマスクを解除することはできません。

doLongStuffは、非同期例外がマスクされていても動作しますが、私が望むように、ブロックされていません。私の実際のコードで

、私はopenDatabaseの外にopenFiledoLongStuffどちらを移動することはできません。実際には、openDatabaseは、任意の数のファイルを開くことができ、および/またはそれがwithDatabaseに復帰したい取り扱う「決定」する前に、さまざまなI/Oを実行します。この制約を受けて、maskコールの内部で実行されても、doLongStuffを割り込み可能にする方法はありますか?

答えて

0

doLongStuffはデータベースで行われていますか?そうであれば、すでに中断可能である可能性があります。 IOを実行するほとんどの関数を含む、ブロックする可能性のある関数がマスクのスコープ内であっても中断される可能性があることを示すInterruptible Operationsの節を参照してください。

あなたはdoLongStuffは(それが使用する機能する依存)割り込み可能であるかどうか、そしてあなたがマスクされたコード内で非同期例外をポーリングするallowInterruptを使用し、あるいはDBからの読み取り同期するためにMVarを使用するかわからない場合。これはほとんどのMVar操作が自分自身で割り込み可能であるために機能し、より大きい関数を割り込み可能にすることができます。

関連する問題