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
Fix WithLatestFrom potential memory visibility issues #247
Conversation
Hi @akarnokd, I'm your friendly neighborhood .NET Foundation Pull Request Bot (You can call me DNFBOT). Thanks for your contribution! TTYL, DNFBOT; |
@akarnokd, Thanks for signing the contribution license agreement so quickly! Actual humans will now validate the agreement and then evaluate the PR. |
Tests passed but then something failed. |
Hi @akarnokd, I'm your friendly neighborhood .NET Foundation Pull Request Bot (You can call me DNFBOT). Thanks for your contribution! The agreement was validated by .NET Foundation and real humans are currently evaluating your PR. TTYL, DNFBOT; |
Please rework to avoid the boxing. I'd prefer a plain old lock over boxing with arbitrary box lifetimes which solely depend on the incoming sequence's timing. |
@bartdesmet That may only be possible if I use locks; I don't know the cost of boxing but I'd assume its less than taking a lock. |
@akarnokd - I'm not as much concerned about the cost of boxing than I am about the effects down the line. In the Bing service I'm working on now, we're very allergic to any boxing without prior knowledge about the eventual lifetime of the box: if it's known to be short-lived, it's ok (if the box can't be avoided at all); if it's known to be very long-lived (ideally infinitely long), it's ok to let it age to Gen-2 (if the box can't be avoided at all); if it's somewhere in the middle, we'll pay the cost during a GC down the line. In this particular case, we're dealing with lifetimes dependent on the velocity of the My recommendation would be to use a |
Okay. I'll change it to use a lock. |
Cool, thanks! Do you still have issues with contribution agreement we have to look into? |
No, found another link and signed it (see cla-already-signed label). |
Updated the PR, not sure what takes so long for the CI (I get access denied is it may not even run yet). |
@@ -39,12 +40,14 @@ public _(WithLatestFrom<TFirst, TSecond, TResult> parent, IObserver<TResult> obs | |||
} | |||
|
|||
private object _gate; | |||
private volatile bool _hasLatest; |
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.
Can you change the field name back to _hasLatest
for consistency and to minimize the diff?
Done. |
👍 |
@shiftkey @bartdesmet @mattpodwysocki is this good to merge? |
As I reported in #227, setting a volatile
hasLatest
doesn't ensure proper visibility of the latest value and one needs at least an ordered store for the whole element (by boxing it and writing the reference in with an ordered store).Cost of correctness: one boxing and one unboxing of structure types.
Possible tradeoff choice: using
Volatile.Write
instead ofInterlocked.Exchange
; both are correct but the former may only become visible a bit delayed (once the CPU write buffer is emitted) whereas the latter is "immediately" visible to other cores.