-
Notifications
You must be signed in to change notification settings - Fork 64
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
withAsync
hangs if called during uninterruptibleMask
#67
Comments
This behaviour makes sense to me, and it's consistent with the documentation. The user is requesting to mask asynchronous exceptions, and that's exactly what they get. Do you really want to call async operations inside |
I agree that it should be generally avoided, but my intuition is that
Note that it's also possible with
And a more real life example:
So |
This question is surprisingly subtle.
So my initial reaction is that "this doesn't match the semantics of mask", which is that child threads inherit the masking state of the parent. That's a simple rule and easy to understand, and there's at least one good reason to do it like this: otherwise there's no way to create a thread in a masked state, which is really (really) important for providing guarantees about your child thread's behaviour. Note that you don't get any guarantees from the fact that nobody else knows the child thread's However, I can see the argument that in many cases having masking be inherited is not useful behaviour.
Take these two examples
and
Would you expect these two to behave the same with respect to async exceptions? I think it would be nice if we could say "yes". That's one of the goals of Furthermore, we would like to implement So at the moment I'm tempted to conclude that you should use Similarly, we might ask why
doesn't work. Is this surprising? Perhaps - but would we then be surprised if
worked? Shouldn't these either both work or both not work? |
I'll close this for now, feel free to re-open if you still think we should do something different here. |
I just ran into this. fpco/unliftio#96 The This is somewhat tricky, because an idiom that we use somewhat often is For a real example in code, consider this function which makes a record available in the database for a test: withRecord rec test =
bracket (runDB $ insert rec) (\id -> runDB $ delete id) test The change I proposed in the withAsync :: MonadUnliftIO m => m a -> (Async a -> m b) -> m b
withAsync a b = withRunInIO $ \run -> do
maskingState <- E.getMaskingState
case maskingState of
E.MaskedUninterruptible ->
A.withAsyncWithUnmask (\unmask -> unmask (run a)) (run . b)
_ ->
A.withAsync (run a) (run . b) I think this brings up the possible points of confusion you mention:
All of these are indeed difficult, but the issue that i ran into is that:
will never terminate! The entire point of |
Consider the following example:
This program hangs forever.
As documentation states,
withAsync
behaves likewithAsync action inner = bracket (async action) uninterruptibleCancel inner
. In this caseuninterruptibleCancel
hangs because the thread which it's trying to kill hasMaskedUninterruptible
masking state.I am not sure if it's supposed to work this way. Maybe it's a bug.
Note that it has the same effect for
race_
andconcurrently_
functions. Both examples below hang:There is a simple workaround for it:
This program doesn't hang. Shouldn't it be the default behaviour? I. e. shouldn't
withAsync
change masking state of spawned thread automatically?The text was updated successfully, but these errors were encountered: