There is a new sheriff in town when it comes to the lock
keyword, And that is the new System.Threading.Lock
type that is introduced in .NET 9. And yes, I know - we still need time to digest the big .NET 8 release.
What is the System.Threading.Lock
type?
Small disclaimer at the beginning: This feature/type is still in preview mode. You can download daily builds of .NET 9 and opt-in to the new Lock
type via the <EnablePreviewFeatures>true</EnablePreviewFeatures>
toggle in your csproj file. That said - there might be breaking changes in the future.
The new Lock
type (sitting in System.Threading.Lock
) has one main purpose: Being a lock. Yes, you can thank me later for that information. But on a serious note, the new type is a lock and a lock only. There is no ambiguity about what it does. Until now, we have done something like:
private readonly object _lock = new object();
public void DoSomething()
{
lock (_lock)
{
// Do something
}
}
The new Lock
type is a bit more explicit about what it does:
private readonly Lock _lock = new Lock();
public void DoSomething()
{
lock (_lock)
{
// Do something
}
}
The usage is absolutely the same (currently, more to that later). But the new type is very explicit and, in theory, can be faster. It depends on the underlying implementation that is used. Until now, always a Monitor
was involved, but that doesn't have to be from now on (well from November 2024).
But the story doesn't end here necessarily. There is a proposal: "Lock statement pattern
". The idea would be to have a bunch of whole new Lock
types. Well, a marker interface like ILockPattern
that is "special handled" by the compiler. So given code like this:
class MyDataStructure
{
private readonly Lock _lock = new();
void Foo()
{
lock (_lock)
{
// do something
}
}
}
Will be lowered by the compiler as such:
class MyDataStructure
{
private readonly Lock _lock = new();
void Foo()
{
using (_lock.EnterLockScope())
{
// do something
}
}
}
Personally, I like reusing the using
pattern for such occasions rather than having "multiple" meanings of lock
(one for the Monitor
and one for the Lock
type or whatever underlying type is used). Like Stephen Clearly's AsyncEx library does it:
AsyncLock _mutex = new AsyncLock();
using (await _mutex.LockAsync())
{
// do something
}
.NET developers are used to the using
pattern, and it is a very clear and concise way to express the intention of the code. As this is just a proposal, we will see where we will land.