Open timcassell opened 1 week ago
Tagging subscribers to this area: @mangod9 See info in area-owners.md if you want to be subscribed.
https://github.com/dotnet/runtime/blob/main/src/coreclr/nativeaot/System.Private.CoreLib/src/System/Threading/Condition.cs is an internal implementation of this used by native AOT.
Should lock
be a constructor parameter instead of being passed into every instance method?
Should
lock
be a constructor parameter instead of being passed into every instance method?
That's the alternative 1 design. I prefer passing it in to each method to be less restrictive so that multiple Lock
instances can use a single ConditionVariable
instance (not at the same time). This makes it possible to pool the objects and use them later without worrying about mapping the exact Lock
object to it. I implemented an AsyncConditionVariable
in my promise library that works this way.
Upon further thought, I can't think of a reason to need to pool individual ConditionVariable
objects. They would typically be used inside a data structure, and if object pooling is needed, the data structure itself can be pooled. So I guess it makes sense to only pass in the Lock
as a constructor argument to reduce overhead and simplify the API.
Perhaps a hypothetical ValueConditionVariable
struct could take a hypothetical ref ValueLock
struct as an argument to each method (to reduce object overhead), and that would more closely match C++'s semantics, but it makes less sense for the ConditionVariable
class. But I'm getting ahead of myself.
I updated the proposal.
@kouvel
Background and motivation
System.Threading.Lock
type was added to replaceMonitor.Enter/Exit
(#34812). No replacements were added forMonitor.Wait/Pulse
.ConditionVariable
is the replacement for those, as well as it can be used locally (Monitor.Wait/Pulse
can only be used globally).It's also .Net's version of C++'s
std::condition_variable
.API Proposal
Notify
naming matches C++, but it could also bePulse
to matchMonitor
instead, or evenSignal
to matchWaitHandle
.API Usage
The pattern using
Monitor
:Converted to using the new types (with C# updated
lock
keyword):More advanced usage that is more cumbersome to implement with
Monitor
:Alternative Designs
Alternative 1 - A
ConditionVariable
may be associated with more than 1Lock
object, but not more than 1 at the same time. TheLock
is passed as an argument to each function, and it's validated internally to be only used by 1Lock
at a time. In C++, using the same condition variable with more than 1 mutex at the same time has undefined behavior. .Net should throw.Alternative 2 - Match
std::condition_variable
more closely.This version does not take the
Lock
object as an argument forNotify(All)
. Even though C++ does it this way, I think it's less safe than passing in theLock
object (we can verify that the notification occurs for the correctLock
object).Open Question
Monitor.Pulse(All)
requires the lock to be held while calling it.std::condition_variable::notify_one
has this in its notes:Should
ConditionVariable.Notify(All)
require the lock to be entered? (It might need it as an implementation detail, I'm not sure.)Risks
None