Not
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Anteckning
Den här artikeln är en funktionsspecifikation. Specifikationen fungerar som designdokument för funktionen. Den innehåller föreslagna specifikationsändringar, tillsammans med information som behövs under utformningen och utvecklingen av funktionen. Dessa artiklar publiceras tills de föreslagna specifikationsändringarna har slutförts och införlivats i den aktuella ECMA-specifikationen.
Det kan finnas vissa skillnader mellan funktionsspecifikationen och den slutförda implementeringen. Dessa skillnader samlas in i de relevanta LDM-anteckningarna (Language Design Meeting) .
Du kan läsa mer om processen för att införa funktionsspecifikationer i C#-språkstandarden i artikeln om specifikationerna.
Champion-utgåva: https://github.com/dotnet/csharplang/issues/7104
Sammanfattning
Specialfall hur System.Threading.Lock interagerar med nyckelordet lock (anropar dess EnterScope metod under huven).
Lägg till statiska analysvarningar för att förhindra oavsiktligt missbruk av typen där det är möjligt.
Motivation
.NET 9 introducerar en ny System.Threading.Lock typ som ett bättre alternativ till befintlig övervakningsbaserad låsning.
Förekomsten av nyckelordet lock i C# kan leda till att utvecklare tror att de kan använda det med den här nya typen.
Detta skulle inte låsas enligt denna typs semantik, utan skulle i stället behandlas som alla andra objekt och använda monitorbaserad låsning.
namespace System.Threading
{
public sealed class Lock
{
public void Enter();
public void Exit();
public Scope EnterScope();
public ref struct Scope
{
public void Dispose();
}
}
}
Detaljerad design
Semantik för låssatsen (§13.13) ändras för att specialhantera System.Threading.Lock-typen.
En
lock-deklaration av formenlock (x) { ... }
- där
xär ett uttryck av typenSystem.Threading.Lock, är exakt detsamma som:ochusing (x.EnterScope()) { ... }System.Threading.Lockmåste ha följande form:namespace System.Threading { public sealed class Lock { public Scope EnterScope(); public ref struct Scope { public void Dispose(); } } }- där
xär ett uttryck för en reference_type, är exakt detsamma som: [...]
Observera att formen kanske inte är helt markerad (t.ex. kommer det inte att finnas några fel eller varningar om den Lock typen inte är sealed), men funktionen kanske inte fungerar som förväntat (t.ex. kommer det inte att finnas några varningar när du konverterar Lock till en härledd typ, eftersom funktionen förutsätter att det inte finns några härledda typer).
Dessutom läggs nya varningar till implicita referenskonverteringar (§10.2.8) vid uppkonvertering av typen System.Threading.Lock.
De implicita referenskonverteringarna är:
- Från alla referenstyp till
objectochdynamic.
- En varning rapporteras när reference_type är känd som
System.Threading.Lock.- Från alla class_type
Still alla class_typeT, förutsatt attShärleds frånT.
- En varning rapporteras när
Sär känd somSystem.Threading.Lock.- Från alla class_type
Still alla interface_typeT, förutsatt attSimplementerarT.
- En varning utfärdas när
Sär känd somSystem.Threading.Lock.- [...]
object l = new System.Threading.Lock(); // warning
lock (l) { } // monitor-based locking is used here
Observera att den här varningen inträffar även för motsvarande explicita konverteringar.
Kompilatorn undviker att rapportera varningen i vissa fall när instansen inte kan låsas efter konvertering till object:
- när konverteringen är implicit och en del av ett anrop för objektjämlikhetsoperator.
var l = new System.Threading.Lock();
if (l != null) // no warning even though `l` is implicitly converted to `object` for `operator!=(object, object)`
// ...
För att komma undan varningen och tvinga fram användning av övervakningsbaserad låsning kan man använda
- det vanliga varningsdämpningsmedlet (
#pragma warning disable), -
MonitorAPI direkt, - indirekt gjutning som
object AsObject<T>(T l) => (object)l;.
Alternativ
Stöd för ett allmänt mönster som andra typer också kan använda för att interagera med nyckelordet
lock. Det här är ett framtida arbete som kan implementeras närref structkan delta i generiska program. Diskuterad i LDM 2023-12-04.För att undvika tvetydigheter mellan den befintliga övervakningsbaserade låsningen och den nya
Lock(eller mönster i framtiden) kan vi:- Introducera en ny syntax i stället för att återanvända den befintliga
lock-instruktionen. - Kräv att de nya låstyperna ska vara
struct(eftersom den befintligalocktillåter inte värdetyper). Det kan uppstå problem med standardkonstruktorer och kopiering om strukturerna har fördröjd initiering.
- Introducera en ny syntax i stället för att återanvända den befintliga
Kodgenen kan härdas mot tråd aborter (som i sig är föråldrade).
Vi kan också varna när
Lockskickas som en typparameter, eftersom låsning på en typparameter alltid använder övervakningsbaserad låsning:M(new Lock()); // could warn here void M<T>(T x) // (specifying `where T : Lock` makes no difference) { lock (x) { } // because this uses Monitor }Det skulle dock orsaka varningar när
Locklagras i en lista som är oönskad:List<Lock> list = new(); list.Add(new Lock()); // would warn hereVi kan inkludera statisk analys för att förhindra användning av
System.Threading.Lockiusings medawaits. Vi kan antingen generera ett fel eller en varning för kod somusing (lockVar.EnterScope()) { await ... }. För närvarande behövs detta inte eftersomLock.Scopeär enref struct, så att koden ändå är ogiltig. Men om vi någonsin tillätref structs iasync-metoder eller ändradeLock.Scopeså att det inte längre är enref struct, skulle denna analys bli till nytta. (Vi skulle sannolikt också behöva överväga detta för alla låstyper som matchar det allmänna mönstret, om det implementeras vid behov i framtiden. Även om det kan behövas en möjlighet att välja bort, eftersom vissa låstyper kan tillåtas användas medawait.) Alternativt kan detta implementeras som en analysator som levereras som en del av körexekveringen.Vi kan lätta på begränsningen som gör att värdetyper inte kan
locked.- för den nya
Locktypen (behövs bara om API-förslaget ändrade det frånclasstillstruct), - för det allmänna mönstret där alla typer kan delta när de implementeras i framtiden.
- för den nya
Vi kan tillåta den nya
lockiasyncmetoder därawaitinte används ilock.- Eftersom
lockför närvarande sänks tillusingmed enref structsom resurs resulterar detta i ett kompileringsfel. Lösningen är att extraheralocktill en separat icke-asyncmetod. - I stället för att använda
ref struct Scopekan vi genereraLock.EnterochLock.Exitmetoder itry/finally. Men metodenExitmåste utlösas när den anropas från en annan tråd änEnter, och därför innehåller den en trådsökning som undviks när du använderScope. - Det bästa vore att tillåta kompilering av
usingpå enref structinomasync-metoder om det inte finns någraawaitiusingkoden.
- Eftersom
Designa möten
-
LDM 2023-05-01: första beslutet att stödja ett
lockmönster - LDM 2023-10-16: sorteras i arbetsuppsättningen för .NET 9
-
LDM 2023-12-04: avvisade det allmänna mönstret, accepterade endast specialhölje
Locktyp + lägga till statiska analysvarningar
C# feature specifications