Lock
개체
메모
이 문서는 기능 사양입니다. 사양은 기능의 디자인 문서 역할을 합니다. 여기에는 기능 디자인 및 개발 중에 필요한 정보와 함께 제안된 사양 변경 내용이 포함됩니다. 이러한 문서는 제안된 사양 변경이 완료되고 현재 ECMA 사양에 통합될 때까지 게시됩니다.
기능 사양과 완료된 구현 간에 약간의 불일치가 있을 수 있습니다. 이러한 차이는 관련LDM(언어 디자인 모임) 노트에서 캡처됩니다.
사양문서에서 기능 스펙릿을 C# 언어 표준에 채택하는 과정에 대해 더 알아볼 수 있습니다.
챔피언 이슈: https://github.com/dotnet/csharplang/issues/7104
요약
System.Threading.Lock
가 lock
키워드와 어떻게 특수하게 상호 작용하는지를 설명합니다 (EnterScope
메서드를 내부적으로 자동 호출하여).
가능한 경우 형식의 실수로 오용되지 않도록 정적 분석 경고를 추가합니다.
동기
.NET 9는 기존 모니터 기반 잠금에 대한 더 나은 대안으로 새로운 System.Threading.Lock
형식 도입했습니다.
C#에 lock
키워드가 있으면 개발자가 이 새 형식으로 사용할 수 있다고 생각할 수 있습니다.
이렇게 하면 이 형식의 의미 체계에 따라 잠기지 않고 대신 다른 개체로 처리하고 모니터 기반 잠금을 사용합니다.
namespace System.Threading
{
public sealed class Lock
{
public void Enter();
public void Exit();
public Scope EnterScope();
public ref struct Scope
{
public void Dispose();
}
}
}
상세 디자인
lock 문(§13.13)의 의미가 System.Threading.Lock
형식의 특정 사례로 변경됩니다.
형식
lock
의 문서lock (x) { ... }
System.Threading.Lock
형식의 표현인x
을 포함하는 은(는), 정확히와(과) 동일하다.및using (x.EnterScope()) { ... }
System.Threading.Lock
는의 형태를 가져야 합니다.namespace System.Threading { public sealed class Lock { public Scope EnterScope(); public ref struct Scope { public void Dispose(); } } }
x
은 reference_type의 표현으로, 정확히 다음과 같습니다: [...]
셰이프가 완전히 확인되지 않을 수 있습니다(예: Lock
형식이 sealed
않은 경우 오류나 경고가 없음). 하지만 기능이 예상대로 작동하지 않을 수 있습니다(예: 기능이 파생 형식이 없다고 가정하므로 Lock
파생 형식으로 변환할 때 경고가 발생하지 않음).
또한 System.Threading.Lock
형식을 업캐스트할 때 암시적 참조 변환(§10.2.8)에 새 경고가 추가됩니다.
암시적 참조 변환은 다음과 같습니다.
- 어떤 reference_type에서
object
및dynamic
로.
- 참조 유형이(가)
System.Threading.Lock
로 알려졌을 때 경고가 보고됩니다.- class_type
S
에서 class_typeT
로, 단S
가T
에서 파생된 경우에만 가능합니다.
S
이System.Threading.Lock
인 것으로 알려지면 경고가 보고됩니다.- 어떤 class_type
S
에서 어떤 interface_typeT
로,S
이T
을 구현하는 경우에 가능합니다.
S
이System.Threading.Lock
인 것으로 알려지면 경고가 보고됩니다.- [...]
object l = new System.Threading.Lock(); // warning
lock (l) { } // monitor-based locking is used here
이 경고는 동등한 명시적 변환에도 발생합니다.
컴파일러는 object
변환한 후 인스턴스를 잠글 수 없는 경우에 경고를 보고하지 않습니다.
- 변환이 암시적이고 개체 같음 연산자 호출의 일부인 경우
var l = new System.Threading.Lock();
if (l != null) // no warning even though `l` is implicitly converted to `object` for `operator!=(object, object)`
// ...
경고를 회피하고 모니터 기반 잠금을 강제로 사용하려면 다음을 사용할 수 있습니다.
- 일반적인 경고 억제 수단(
#pragma warning disable
) -
Monitor
API를 직접 -
object AsObject<T>(T l) => (object)l;
같은 간접 캐스팅.
대안
다른 형식이
lock
키워드와 상호 작용하는 데 사용할 수 있는 일반적인 패턴을 지원합니다. 이는ref struct
제네릭에 참여할 수 있을 때 구현될 수 있는 향후 작업입니다. LDM 2023-12-04에서 논의했습니다.기존 모니터 기반 잠금과 새
Lock
(또는 향후 패턴) 간의 모호성을 방지하기 위해 다음을 수행할 수 있습니다.- 기존
lock
문을 다시 사용하는 대신 새 구문을 소개합니다. - 새 잠금 형식을
struct
로 지정해야 합니다 (기존lock
은 값 유형을 허용하지 않음). 구조체에 지연 초기화가 있는 경우 기본 생성자 및 복사에 문제가 있을 수 있습니다.
- 기존
codegen은 더 이상 사용되지 않는 스레드 중단에 대해 강력해질 수 있습니다.
형식 매개 변수에 대한 잠금은 항상 모니터 기반 잠금을 사용하므로
Lock
형식 매개 변수로 전달되는 경우에도 경고할 수 있습니다.M(new Lock()); // could warn here void M<T>(T x) // (specifying `where T : Lock` makes no difference) { lock (x) { } // because this uses Monitor }
그러나 바람직하지 않은 목록에
Lock
저장할 때 경고가 발생합니다.List<Lock> list = new(); list.Add(new Lock()); // would warn here
using
과await
에서System.Threading.Lock
사용을 방지하기 위해 정적 분석을 포함할 수 있습니다. 즉,using (lockVar.EnterScope()) { await ... }
같은 코드에 대해 오류나 경고를 발생시킬 수 있습니다. 현재는Lock.Scope
이ref struct
이기 때문에 해당 코드는 어차피 불법이어서 필요하지 않습니다. 그러나ref struct
을async
메서드에 허용하거나Lock.Scope
가ref struct
이 되지 않도록 변경한 경우, 이 분석이 유익해질 것입니다. 또한 나중에 구현되는 경우 모든 잠금 형식이 일반 패턴과 일치하는지를 고려해야 할 가능성이 있습니다. 일부 잠금 형식은await
과 함께 사용할 수 있으므로, 이를 위한 옵트아웃 메커니즘이 필요할 수 있습니다.) 또는, 이는 런타임의 일부로 제공되는 분석기로 구현할 수 있습니다.값 형식을
lock
수 없다는 제한을 완화할 수 있습니다.- 새
Lock
형식의 경우(API 제안이class
에서struct
로 변경된 경우에만 필요) - 는 나중에 구현될 때 모든 형식이 참여할 수 있는 일반 패턴입니다.
- 새
lock
내에서await
사용되지 않는async
메서드에서 새lock
허용할 수 있습니다.- 현재
ref struct
를 리소스로 사용하여lock
이using
로 낮춰지면서 컴파일 시 오류가 발생합니다. 해결 방법은lock
별도의 비async
메서드로 추출하는 것입니다. -
ref struct Scope
사용하는 대신try
/finally
Lock.Enter
및Lock.Exit
메서드를 내보낸다. 그러나Exit
메서드는Enter
과 다른 스레드에서 호출될 경우 반드시 예외를 던져야 하므로, 이러한 상황을 처리하기 위해 스레드 조회를 포함하며, 이는Scope
를 사용하면 방지됩니다. -
using
본문 내에await
이 없는 경우,async
메서드에서ref struct
을 사용하여using
을 컴파일하는 것이 가장 좋습니다.
- 현재
디자인 회의
-
LDM 2023-05-01:
lock
패턴을 지원하기 위한 초기 결정 - LDM 2023-10-16: .NET 9의 작업 집합에 포함됨
-
LDM 2023-12-04: 일반 패턴을 거부하고,
Lock
유형에 대한 특수 처리를 허용하며 정적 분석 경고를 추가함.
C# feature specifications