2012-01-27 5 views
5

데이터베이스 라이브러리를 작성하고 있습니다. 기본 기능은 다음과 같습니다.비동기 예외 중첩 된 마스크

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

데이터베이스 핸들의 수명을 자동으로 관리합니다.

내부적으로 withDatabasebracket 기능을 사용합니다.. 내 특정 경우

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) 

이 코드가 의도 한 효과를 내지는 못합니다.

것은 이제 withDatabase 다시 보자, 그 정의와 bracket 대체이 시간 :

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

문서에 대한 : 실행의 특정 시점에서

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

는, 호출 스택은 다음이된다 Control.Exception 모듈에 중첩 호출에 대해 뭔가가 있습니다 :

mask 인수에 전달 된 restore 동작이 비동기 예외를 반드시 해제하지는 않으며 마스킹 상태를 둘러싸는 컨텍스트의 복원 상태로 복원한다는 점에 유의하십시오. 따라서 비동기 예외가 이미 마스크 된 경우 마스크를 사용하여 예외를 다시 언 마스킹 할 수 없습니다.

doLongStuff은 비동기식 예외가 마스크 된 상태에서 작동하며, 원하는대로 차단 해제되지 않습니다.

내 진짜 코드에서

, 나는 openDatabase에서 openFiledoLongStuff도 이동할 수 없습니다 : 사실, openDatabase 파일의 임의의 숫자를 열 수 및/또는 그 withDatabase로 돌아 싶어 처리하는 "결정"전에 다양한 I/O를 수행 . 이 단점을 감안할 때 doLongStuff이 중첩 된 mask 호출 내에서 실행 되더라도 중단 될 수있는 방법이 있습니까?

답변

0

doLongStuff이 데이터베이스에서 수행되고 있습니까? 그렇다면 이미 인터럽트 가능할 수 있습니다. IO를 수행하는 대부분의 기능을 포함하여 차단할 수있는 기능이 마스크 범위 내 에서조차 중단 될 수 있다는 내용의 Interruptible Operations 섹션을 참조하십시오. doLongStuff가 인터럽트인지 아닌지 확실하지 않은 경우

는 다음 중 하나를 DB에서 읽기 동기화하는 MVar를 사용하여 선택적으로 마스크 코드 내에서 비동기 예외를 올릴 수 allowInterrupt를 사용하거나 할 수 있습니다 (이 사용하는 기능 따라 다름) . 대부분의 MVar 작업이 자체적으로 인터럽트 가능하기 때문에 더 큰 기능을 방해 할 수 있으므로이 작업이 가능합니다.

관련 문제