-
Notifications
You must be signed in to change notification settings - Fork 109
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
Documentation is misleading w.r.t. guarantees provided regarding side effects #83
Comments
I’ll clarify this in the docs, but OnceCell does establish happens before
relationship: it wouldn’t be sound otherwise
…On Thursday, 2 January 2020, Brian Smith ***@***.***> wrote:
The documentation says that the "Implementation is based on lazy_static
and lazy_cell crates and std::sync::Once. In some sense, once_cell just
streamlines and unifies those APIs To implement a sync flavor of OnceCell,
this crates uses either a custom re-implementation of std::sync::Once or
parking_lot::Mutex."
This creates some confusion about how equivalent once_cell::OnceCell is
to std::sync::Once. In particular, std::sync::Once guarantees that "When
this function returns, it is guaranteed that some initialization has run
and completed (it may not be the closure specified). It is also guaranteed
that any memory writes performed by the executed closure can be reliably
observed by other threads at this point (there is a happens-before relation
between the closure and code executing after the return)."
Is this guarantee provided by OnceCell? I don't think you intend it to be
provided, but the statements above in the documentation might lead one to
think that OnceCell is a reimplementation of std::sync::Once with a
different (better) API, when really it implements a similar but more
limited (and potentially more efficient) variant.
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub
<#83?email_source=notifications&email_token=AANB3M7FOVJ7UJLUVJGQU3DQ3ZTGDA5CNFSM4KCHL352YY3PNVWWK3TUL52HS4DFUVEXG43VMWVGG33NNVSW45C7NFSM4IDYTJXQ>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AANB3MZUKDX7FTPZGEMESM3Q3ZTGDANCNFSM4KCHL35Q>
.
|
Thanks for the report! It was a major oversight in the documentation, as these grantees are really crucial. And of course I am completely wrong claiming that " it wouldn’t be sound otherwise", and you are right that there's a potentially more efficient implementation via However, for this crate I want to stick to a conservative
That said, I think that for std we maybe should spec that the ordering is consume: I would feel better about faking consume via relaxed in std, b/c it is bound to the specific compiler and can rely on implementaiton defined behavior. I also think that we could add a separate |
Just to clarify: The issue isn't about the ordering guarantees for values stored within the |
I think After you ship a release with #85 it will be pretty much impossible to undo that decision without renaming |
The problem is that we can't actually take advantage of this weaker guarantee in current Rust, without involving implementation-defined behavior. Rust does not provide
I don't want to ship a vaguely correct synchronization primitive as a default in a foundation-level library. We can of course document weaker guarantees but implement stronger ones, in hope that we'll improve implementation once it becomes possible to do in a language-lawer correct way. However, A plan outlined in #71 (comment) seems better, in practice. We ship a vaguely correct, but more efficient implementation as an opt-in module For standard library, we can't add a separate feature-flaged module or issue 2.0, so we should stick to a more conservative default. At the same time, standard library can rely on implementation-defined behavior (b/c it is paired with the compiler version), so we would actually be able to ship a more performant implementation in std before sorting out consume formally. That is, the risk I see with using crossbeam's hack right now is that a compiler upgrade may, in theory, break the code. And, in theory, people might be compiling |
That's my preference. However, I think the choice you've chosen also makes sense. I agree it is risky, too risky, to implement this with a hack. |
The documentation says that the "Implementation is based on lazy_static and lazy_cell crates and std::sync::Once. In some sense, once_cell just streamlines and unifies those APIs To implement a sync flavor of OnceCell, this crates uses either a custom re-implementation of std::sync::Once or parking_lot::Mutex."
This creates some confusion about how equivalent
once_cell::OnceCell
is tostd::sync::Once
. In particular,std::sync::Once
guarantees that "When this function returns, it is guaranteed that some initialization has run and completed (it may not be the closure specified). It is also guaranteed that any memory writes performed by the executed closure can be reliably observed by other threads at this point (there is a happens-before relation between the closure and code executing after the return)."Is this guarantee provided by
OnceCell
? I don't think you intend it to be provided, but the statements above in the documentation might lead one to think thatOnceCell
is a reimplementation ofstd::sync::Once
with a different (better) API, when really it implements a similar but more limited (and potentially more efficient) variant.The text was updated successfully, but these errors were encountered: