Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
Notitie
Dit artikel is een functiespecificatie. De specificatie fungeert als het ontwerpdocument voor de functie. Het bevat voorgestelde specificatiewijzigingen, samen met informatie die nodig is tijdens het ontwerp en de ontwikkeling van de functie. Deze artikelen worden gepubliceerd totdat de voorgestelde specificaties zijn voltooid en opgenomen in de huidige ECMA-specificatie.
Er kunnen enkele verschillen zijn tussen de functiespecificatie en de voltooide implementatie. De verschillen zijn vastgelegd in de relevante verslagen (Language Design Meeting).
Meer informatie over het proces voor het aannemen van functiespeclets in de C#-taalstandaard vindt u in het artikel over de specificaties.
Probleem met Champion: https://github.com/dotnet/csharplang/issues/7104
Samenvatting
Speciaal geval voor hoe System.Threading.Lock samenwerkt met het lock trefwoord (waarbij de EnterScope methode achter de schermen wordt aangeroepen).
Voeg waar mogelijk statische analysewaarschuwingen toe om onbedoeld misbruik van het type te voorkomen.
Motivatie
.NET 9 introduceert een nieuw System.Threading.Lock type als een beter alternatief voor bestaande monitor-gebaseerde vergrendeling.
De aanwezigheid van het lock trefwoord in C# kan ertoe leiden dat ontwikkelaars denken dat ze het kunnen gebruiken met dit nieuwe type.
Dit zou niet worden vergrendeld volgens de semantiek van dit type, maar zou het als een gewoon object behandelen en gebruikmaken van monitor-gebaseerde vergrendeling.
namespace System.Threading
{
public sealed class Lock
{
public void Enter();
public void Exit();
public Scope EnterScope();
public ref struct Scope
{
public void Dispose();
}
}
}
Gedetailleerd ontwerp
Semantiek van de vergrendelingsinstructie (§13.13) wordt gewijzigd om een speciaal geval te maken voor het System.Threading.Lock type.
Een
lockverklaring van de vormlock (x) { ... }
- waarbij
xeen expressie van het typeSystem.Threading.Lockis, precies gelijk is aan:enusing (x.EnterScope()) { ... }System.Threading.Lockmoeten de volgende vorm hebben:namespace System.Threading { public sealed class Lock { public Scope EnterScope(); public ref struct Scope { public void Dispose(); } } }- wanneer
xeen expressie is van een reference_type, precies gelijk is aan: [...]
Houd er rekening mee dat de shape mogelijk niet volledig is ingeschakeld (er zijn bijvoorbeeld geen fouten of waarschuwingen als het Lock type niet is sealed), maar de functie werkt mogelijk niet zoals verwacht (er zijn bijvoorbeeld geen waarschuwingen bij het converteren van Lock naar een afgeleid type, omdat de functie ervan uitgaat dat er geen afgeleide typen zijn).
Daarnaast worden er nieuwe waarschuwingen toegevoegd aan impliciete verwijzingsconversies (§10.2.8) bij het upcasten van het System.Threading.Lock type:
De impliciete verwijzingsconversies zijn:
- Van elke reference_type tot
objectendynamic.
- een waarschuwing wordt gemeld wanneer de reference_type bekend is
System.Threading.Lock.- Van elke class_type
Stot een class_typeT, mitsSis afgeleid vanT.
- Er wordt een waarschuwing gerapporteerd wanneer
Sbekend is alsSystem.Threading.Lock.- Van elke class_type
Snaar een interface_typeT, mitsSTimplementeert.
- Er wordt een waarschuwing gerapporteerd wanneer
Sbekend is alsSystem.Threading.Lock.- [...]
object l = new System.Threading.Lock(); // warning
lock (l) { } // monitor-based locking is used here
Houd er rekening mee dat deze waarschuwing optreedt, zelfs voor gelijkwaardige expliciete conversies.
De compiler vermijdt het rapporteren van de waarschuwing in sommige gevallen wanneer het exemplaar niet kan worden vergrendeld nadat het is geconverteerd naar object:
- wanneer de conversie impliciet is en deel uitmaakt van een aanroep van een object gelijkheidsoperator.
var l = new System.Threading.Lock();
if (l != null) // no warning even though `l` is implicitly converted to `object` for `operator!=(object, object)`
// ...
Als u de waarschuwing wilt negeren en toch vergrendeling op basis van monitor wilt gebruiken, kunt u
- de gebruikelijke middelen voor het onderdrukken van waarschuwingen (
#pragma warning disable), - api's rechtstreeks
Monitor, - indirect gieten zoals
object AsObject<T>(T l) => (object)l;.
Alternatieven
Ondersteuning voor een algemeen patroon dat andere typen ook kunnen gebruiken om te communiceren met het
locktrefwoord. Dit is een toekomstig werk dat kan worden geïmplementeerd wanneerref structs kunnen deelnemen aan generics. Besproken in LDM 2023-12-04.Om dubbelzinnigheid tussen de bestaande monitorvergrendeling en de nieuwe
Lock(of patroon in de toekomst) te voorkomen, kunnen we het volgende doen:- Introduceer een nieuwe syntaxis in plaats van de bestaande
lock-instructie opnieuw te gebruiken. - Vereisen dat de nieuwe vergrendelingstypen
structzijn (omdat de bestaandelockwaardetypen niet toestaan). Er kunnen problemen zijn met standaardconstructors en kopiëren als de structs luie initialisatie hebben.
- Introduceer een nieuwe syntaxis in plaats van de bestaande
Het gegenereerde code kan worden versterkt om bestand te zijn tegen het afbreken van threads (die zelf al verouderd zijn).
We kunnen ook waarschuwen wanneer
Lockwordt doorgegeven als een typeparameter, omdat het vergrendelen van een typeparameter altijd gebruikmaakt van op monitor gebaseerde vergrendeling:M(new Lock()); // could warn here void M<T>(T x) // (specifying `where T : Lock` makes no difference) { lock (x) { } // because this uses Monitor }Dit zou echter waarschuwingen veroorzaken bij het opslaan van
Locks in een lijst die ongewenst is:List<Lock> list = new(); list.Add(new Lock()); // would warn hereWe kunnen statische analyses opnemen om het gebruik van
System.Threading.Lockinusingmetawaits te voorkomen. Dat wil zeggen, we kunnen een fout of een waarschuwing geven voor code zoalsusing (lockVar.EnterScope()) { await ... }. Dit is momenteel niet nodig omdatLock.Scopeeenref structis, zodat code toch illegaal is. Als we echter ooitref structinasyncmethoden hebben toegestaan ofLock.Scopehebben gewijzigd om geenref structte zijn, zou deze analyse nuttig worden. (We moeten waarschijnlijk ook rekening houden met deze vergrendelingstypen die overeenkomen met het algemene patroon als deze in de toekomst worden geïmplementeerd. Hoewel er mogelijk een opt-outmechanisme moet zijn, omdat sommige vergrendelingstypen mogelijk kunnen worden gebruikt metawait.) U kunt dit ook implementeren als een analyse die wordt verzonden als onderdeel van de runtime.We zouden de beperking dat waardetypen niet kunnen worden
locked kunnen versoepelen.- voor het nieuwe
Locktype (alleen nodig als het API-voorstel dit heeft gewijzigd vanclassinstruct), - voor het algemene patroon waarbij elk type kan deelnemen wanneer dit in de toekomst wordt geïmplementeerd.
- voor het nieuwe
We kunnen de nieuwe
lockinasyncmethoden toestaan waarbijawaitniet in delockwordt gebruikt.- Omdat
lockmomenteel wordt verlaagd totusingmet eenref structals de resource, resulteert dit in een compilatietijdfout. De tijdelijke oplossing is om delockte extraheren in een aparte methode die geenasyncis. - In plaats van de
ref struct Scopete gebruiken, kunnen weLock.EnterenLock.Exitmethoden intry/finallyverzenden. De methodeExitmoet echter worden gegooid wanneer deze wordt aangeroepen vanuit een andere thread danEnter, waardoor deze een threadzoekactie bevat die wordt vermeden bij het gebruik van deScope. - Het beste zou zijn om compilatie van
usingop eenref structin dezeasync-methoden toe te staan, op voorwaarde dat er geenawaitin deusing-hoofdtekst aanwezig is.
- Omdat
Ontwerpvergaderingen
-
LDM 2023-05-01: eerste beslissing om een
lockpatroon te ondersteunen - LDM 2023-10-16: ingedeeld in de werkset voor .NET 9
-
LDM 2023-12-04: het algemene patroon afgewezen, alleen het type
Lockmet speciale behuizing geaccepteerd en waarschuwingen voor statische analyse toevoegen
C# feature specifications