Status() doesn't need a lock #717
Merged
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Reading the status of an IAsyncXxx does not require a lock because the operation is already inherently racy. Change the
m_statusto astd::atomicso we can access it from multiple threads without a lock. Everybody who accesses it under a lock can usestd::memory_order_relaxedbecause the lock is providing the memory ordering protection. TheStatus()method uses acquire order to handle the case where one thread publishes the IAsyncXxx with release semantics, and another thread picks it up and interrogates the status. Causality requires us to report the status that was published by the first thread, so we need acquire.Reading the value while another thread is changing it is okay, as long as we get either the entire old value or the entire new value, which is what
std::atomicguarantees. If we read a stale value, that's okay, because multithreading means that we could have executed a few cycles sooner, in which case the stale value was current at the time.If anybody makes a decision based on the status, they will have to return to the IAsyncXxx to get the Result or the ErrorCode, and those will take the lock and ensure consistency of the other protected members.
This change remove a lock from the
await_transformmethod, which would otherwise need to be entered (and exited) at everyco_awaitoperation. The code sequencebecomes
which avoids two calls, frees up a nonvolatile register, and avoid a spill of volatile registers.
Relaxed order access to atomics is implemented as a simple load or store on all supported platforms, so the change from a simple variable to a
std::atomichas no code generation effect for all of the other uses.