I’m trying to figure out how an open socket or file handle should interact with continuations. Searching has revealed that dynamic-wind
is probably part of the solution, but I’m more interested in the methodology rather than the implementation, and all I could find is how to implement it under various conditions.
Do programmers even use sockets within continuations in such a way that it is necessary for dynamic-wind
to close them? Or is it typically just a way to implement a “finally” block if the continuation exits past where the socket is handled?
What should happen if a continuation is re-entered after a hypothetical dynamic-wind
closes the socket?
1
It is common to automatically close files, sockets, and other resources when the program uses a continuation (or exception, which is often implemented using continuations) to exit a context. There are often library procedures that help do this automatically; for example, see Racket’s call-with-input-file*, call-with-semaphore, etc. They all use dynamic-wind
in their implementation.
It’s often difficult to write code that uses or manages resources correctly in the presence of continuations. For example, if a file gets closed when control jumps out, should it be re-opened when control jumps back in? If so, maybe it needs to be opened in a different mode the second time, eg append instead of truncate. But now it may be difficult to ensure that the output is well-formed; continuation jumps may mean that parts get written multiple times, out of order, etc. And so on. So it’s often useful to simply prohibit continuation jumps back into a context once it’s been exited. Racket provides call-with-continuation-barrier
for this purpose, but it can also be done with dynamic-wind
and a mutable variable.
(One difference between using call-with-continuation-barrier
and dynamic-wind
is that you use call-with-continuation-barrier
around your call to unknown code, whereas dynamic-wind
would need to be around the beginning of the code that you want to protect from reentry, which may be harder to determine. There’s a mailing-list post with more detailed discussion.)
The story is about the same for delimited continuations. For example, shift
jumps out across boundaries, and applying the procedure it gives you jumps in across the captured context boundaries.