데이터베이스 라이브러리를 작성하고 있습니다. 기본 기능은 다음과 같습니다.비동기 예외 중첩 된 마스크
withDatabase :: FilePath -> (DBHandle -> IO a) -> IO a
데이터베이스 핸들의 수명을 자동으로 관리합니다.
내부적으로 withDatabase
은 의 bracket
기능을 사용합니다.. 내 특정 경우
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
에서 openFile
도 doLongStuff
도 이동할 수 없습니다 : 사실, openDatabase
파일의 임의의 숫자를 열 수 및/또는 그 withDatabase
로 돌아 싶어 처리하는 "결정"전에 다양한 I/O를 수행 . 이 단점을 감안할 때 doLongStuff
이 중첩 된 mask
호출 내에서 실행 되더라도 중단 될 수있는 방법이 있습니까?