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

Lazy values are not guaranteed to be evaluated just once if accessed concurrently #566

Open
anfelor opened this issue Jul 25, 2024 · 0 comments

Comments

@anfelor
Copy link
Collaborator

anfelor commented Jul 25, 2024

In a multi-core setting, it is possible for two threads to read the reference of an uninitialized lazy value and execute the action concurrently:

// Force a delayed value; the value is computed only on the first
// call to `force` and cached afterwards.
pub fun force( delayed : delayed<e,a> ) : e a
unsafe-total
val r = delayed.dref
match !r
Right(x) -> x
Left(action) ->
val x = mask-st{ mask<div>(action) }()
r := Right(x)
x

This implementation is sound for pure computations where duplicate evaluation can not be observed, but not for arbitrary algebraic effects. This mirrors the issue that Haskell had with lazy thunks containing unsafePerformIO. We could solve this problem by using an atomic compare and swap operation instead of the read instruction that puts a special Blackhole value into the reference and blocks if there is already a blackhole value in the thunk. While this is potentially expensive, it is only necessary if the value is thread-shared and we can continue using this faster implementation otherwise.

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

No branches or pull requests

1 participant