When you want to acquire a resource, do some work with it, and then
release the resource, it is a good idea to use
bracket, because
bracket will install the necessary exception handler to release
the resource in the event that an exception is raised during the
computation. If an exception is raised, then
bracket will
re-raise the exception (after performing the release).
A common example is opening a file:
bracket
(openFile "filename" ReadMode)
(hClose)
(\fileHandle -> do { ... })
The arguments to
bracket are in this order so that we can
partially apply it, e.g.:
withFile name mode = bracket (openFile name mode) hClose
Bracket wraps the release action with
mask, which is sufficient
to ensure that the release action executes to completion when it does
not invoke any interruptible actions, even in the presence of
asynchronous exceptions. For example,
hClose is
uninterruptible when it is not racing other uses of the handle.
Similarly, closing a socket (from "network" package) is also
uninterruptible under similar conditions. An example of an
interruptible action is
killThread. Completion of interruptible
release actions can be ensured by wrapping them in in
uninterruptibleMask_, but this risks making the program
non-responsive to
Control-C, or timeouts. Another option is
to run the release action asynchronously in its own thread:
void $ uninterruptibleMask_ $ forkIO $ do { ... }
The resource will be released as soon as possible, but the thread that
invoked bracket will not block in an uninterruptible state.