-
Notifications
You must be signed in to change notification settings - Fork 196
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
The MonadUnliftIO instance of ResourceT makes it incredibly tricky to use with threads #425
Comments
On further thinking I don't think this is enough, there is no way for a user to know that the |
I agree that the current situation is unsatisfying, but the case you're hitting is relatively rare, and the solutions all involve a significant overhead. Perhaps using The reason this is rare in my experience is that, by using functions like |
Maybe is a quicker/simpler stopgap there should be a bracketing function like:
Which gets the current resource map and returns a bracketing function which wraps another computation with increments/decrements of the resource map, so that library authors (i.e., me ;)) can simply do: foo = do
withRes <- withResources
forkIO $ withRes actualComputation To more easily fix this issue (I have, essentially, implemented this in my own code, now, but it relies on stateAlloc and cleanState from |
Even that isn't sufficient, though it may help. There's a race condition in whether |
Ah, yeah...my own fix was paranoid enough to prevent that (I call stateAlloc before forking and then install a cleanup at thread exit), but I couldn't think of a convenient API to make that accessible... |
I was using MonadUnliftIO so I could easily parallelise functions by running them in multiple threads, but after a refactoring to use more parallelism I've started noticing some errors from
ResourceT
about cleanup being triggered/accessed after freeing.After diving through a bunch of sources, this seems to be fairly obviously caused by the fact that the MonadUnliftIO instance of ResourceT naively duplicates the IORef that tracks all the cleanups. The end result is that every thread independently ends up running the cleanup on these resources, hence triggering an
InvalidAccess
exception.I can't simply use
resourceForkWith
orresourceForkIO
because my code doesn't use/isn't aware ofResourceT
, but I also have no way to stop users from passing me functions that useResourceT
somewhere internally, which will end up causing all sorts of failures.I think maybe there should be an additional
MonadUnliftIOThreadSafe
(or whatever) class that is restricted to monads that are safe to run in separate threads and not implementing it for ResourceT (I'm not sure whether this should be an issue with unliftio-core rather than resourcet...)The text was updated successfully, but these errors were encountered: