A coroutine doesn't do anything more than a callback does -- it's just syntactic sugar.

The default behaviour of many asynchronous systems is to extend the lifetime of context data until all the asynchronous handlers have run. You can also just bind them to the resource instead which is arguably more elegant, but which depends on how cancellation is implemented.