-
Notifications
You must be signed in to change notification settings - Fork 31
Fix race condition in AsyncCurrentValueSubject
#40
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
base: main
Are you sure you want to change the base?
Fix race condition in AsyncCurrentValueSubject
#40
Conversation
|
Hello! I encountered a similar problem. This fix seems to help me. Is there a plan to merge? |
|
@codex review |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 29ad29a4ad
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| let consumerId = self.state.withCriticalRegion { state -> Int in | ||
| state.ids += 1 | ||
| state.channels[state.ids] = asyncBufferedChannel | ||
| asyncBufferedChannel.send(state.current) | ||
| return state.ids |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Avoid resuming consumers while holding subject lock
Calling asyncBufferedChannel.send(state.current) while inside state.withCriticalRegion can synchronously resume an awaiting consumer. If that consumer’s code touches the subject again (e.g., reads value or calls send), it will try to re-enter the same ManagedCriticalState that uses a non‑reentrant os_unfair_lock, leading to a deadlock. This only occurs when a consumer awaits the channel and then re-enters the subject on receipt, but that pattern is common in for‑await loops.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@codex What do you suggest that solves the initial issue while avoiding re-entrency ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@codex What do you suggest that solves the initial issue while avoiding re-entrency ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Codex couldn't complete this request. Try again later.
| let consumerId = self.state.withCriticalRegion { state -> Int in | ||
| state.ids += 1 | ||
| state.channels[state.ids] = asyncBufferedChannel | ||
| asyncBufferedChannel.send(state.current) | ||
| return state.ids |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Avoid resuming consumers while holding subject lock
Calling asyncBufferedChannel.send(state.current) while inside state.withCriticalRegion can synchronously resume an awaiting consumer. If that consumer’s code touches the subject again (e.g., reads value or calls send), it will try to re-enter the same ManagedCriticalState that uses a non‑reentrant os_unfair_lock, leading to a deadlock. This only occurs when a consumer awaits the channel and then re-enters the subject on receipt, but that pattern is common in for‑await loops.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@codex What do you suggest that solves the initial issue while avoiding re-entrency ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To use Codex here, create an environment for this repo.
Description
If a value is sent to the subject while
handleNewConsumer()is running, it is possible for the new consumer to miss this value. This is because thecurrentValueis read before the state is updated with the channel. This is addressed by setting the current value at the same point that the channel is added to the state.Checklist