Skip to content
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

4.x: Inline SerialDisposable usages #593

Merged
merged 3 commits into from
Jun 15, 2018

Conversation

akarnokd
Copy link
Collaborator

This PR inlines the usage of the SerialDisposable class into a field and Disposable.TrySetSerial calls.

_subscription.Disposable = d;
d.Disposable = result.SubscribeSafe(new HandlerObserver(this));
_once = true;
Disposable.TrySetSerial(ref _subscription, result.SubscribeSafe(this));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I might not ever get threading right and be stuck with using lock forever, but aren't we introducing a race here, since the subscription might invoke OnError on a different thread almost immediately, and _once is not protected by anything, it's not a volatile write and there's no locks.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whenever this is handed to another thread, there is a barrier inside the scheduler or task start that establishes a happens-before, so setting _once to true should be always visible to the next call to OnError.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got reference?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where is the specific part about this being passed to another thread?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's implicit as it is just another value/variable: See the "Full memory barrier" section about what constitutes as barrier and thus anything set before that will be visible after (provided that no further changes happen on the original thread to those references).

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But we don't know nothing about how the work will be unloaded to another thread, threre might not be a new thread or a Task.Start. It might just go onto an existing EventLoopScheduler and be picked up from there.

Copy link
Collaborator Author

@akarnokd akarnokd Jun 15, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Such async boundaries will go through eventually a lock or an atomic CAS/Exchange which are full barriers. If they didn't, everything else would break way before this field is ever read.

https://github.com/dotnet/reactive/blob/master/Rx.NET/Source/src/System.Reactive/Concurrency/EventLoopScheduler.cs#L154

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please, just make it a Volatile.Write for now and push that optimization to a separate PR. I'm really not convinced but my experience with lock-free programming is also limited. Thus I can't merge it as it is in good faith.

@danielcweber danielcweber merged commit 50bbdab into dotnet:master Jun 15, 2018
@akarnokd akarnokd deleted the SerialDisposableInline branch June 26, 2018 21:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants