Introduction To Locking And Concurrency Control in .NET 6
Tags: aspnet, aspnetcore, dotnet, csharp
Published: 2023-09-10 07:57:48

---
title: Introduction To Locking And Concurrency Control in .NET 6
published: true
date: 2022-10-22 00:00:00 UTC
tags: aspnet,aspnetcore,dotnet,csharp
canonical_url: https://www.milanjovanovic.tech/blog/introduction-to-locking-and-concurrency-control-in-dotnet-6
cover_image: https://dev-to-uploads.s3.amazonaws.com/uploads/articles/zs0v9nx8gnscoo4zklhv.png
---
In this week's newsletter, we'll see how we can work with **locking** in **.NET 6**.

We won't talk about how the lock is actually implemented at the operating system level. We will focus on application-level **locking** mechanisms instead.

**Locking** allows us to control how many **threads** can access some piece of code. Why would you want to do this?

Usually because you want to protect access to **expensive resources** , and you need the **concurrency control** that locking enables.

We will use a simple `BankAccount` class with a `Deposit` method to illustrate how to implement locking.

## The C# Lock Statement

The C# language supports locking with the [`lock` statement](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/statements/lock). You can use the `lock` statement to define a code block that only one thread can access.

The `lock` statement acquires a mutual-exclusion lock (mutex) for a given object, executes the statement block, and releases the lock.

```csharp
lock(_lock)
{
   // Your code...
}
```

Here `_lock` is a reference type, usually an `object` instance.

Let's see how we can implement the `BankAccount` class using the `lock` statement:

```csharp
public class BankAccount
{
   private static readonly object _lock = new();
   private decimal _balance;

   public void Deposit(decimal amount)
   {
      lock(_lock)
      {
         _balance += amount;
      }
   }
}
```

The first thread to reach and execute the `lock` statement will be allowed to update the `_balance`. Any other threads will block until the lock is released.

## Locking With Semaphore

The [`Semaphore`](https://learn.microsoft.com/en-us/dotnet/api/system.threading.semaphore?view=net-6.0)class is another option we can use to achieve the same effect.

We'll use the `Semaphore` constructor to set the `initialCount` to 0, which means that the `Semaphore` is open at the start. And we will also set the `maximumCount` to 1, which means that only one thread is allowed to enter the `Semaphore`.

Let's see how we can implement the `BankAccount` class using the `Semaphore`:

```csharp
public class BankAccount
{
   private static readonly Semaphore _semaphore = new(
      initialCount: 0,
      maximumCount: 1);

   private decimal _balance;

   public void Deposit(decimal amount)
   {
      _semaphore.WaitOne();

      _balance += amount;

      _semaphore.Release();
   }
}
```

To enter the `Semaphore`, we have to call the `WaitOne` method.

If no thread was previously inside, our thread is allowed to enter the `Semaphore` and update the balance.

After updating the balance, we call the `Release` method to release the `Semaphore` for other threads that might be waiting.

## Asynchronous Locking With SemaphoreSlim

What if we wanted to call an asynchronous method in a locked context?

We can't use the `lock` statement as it doesn't support asynchronous calls. Awaiting an asynchronous call inside a `lock` statement will cause a compilation error.

The `Semaphore` class can solve this problem.

But I want to show you another option that we have, [`SemaphoreSlim`](https://learn.microsoft.com/en-us/dotnet/api/system.threading.semaphoreslim?view=net-6.0). It's a lightweight alternative to the `Semaphore` class and has `async` methods.

Let's see how we can implement the `BankAccount` class using `SemaphoreSlim`:

```csharp
public class BankAccount
{
   private static readonly SemaphoreSlim _semaphore = new(
      initialCount: 0,
      maximumCount: 1);

   private decimal _balance;

   public async Task Deposit(decimal amount)
   {
      await _semaphore.WaitAsync();

      _balance += amount;

      _semaphore.Release();
   }
}
```

Notice that I updated the `Deposit` method to return a `Task`.

This time, we're calling `WaitAsync` to block the current thread until it can enter the semaphore.

After updating the balance, we call the `Release` method to release the `SemaphoreSlim` like in the previous example.

## Are There Other Options For Locking in .NET?

So far I mentioned three options to implement locking:

- `lock` statement
- `Semaphore`
- `SemaphoreSlim`

However, **.NET** has other classes for **concurrency control** that you can explore like[`Monitor`](https://learn.microsoft.com/en-us/dotnet/api/system.threading.monitor?view=net-6.0),[`Mutex`](https://learn.microsoft.com/en-us/dotnet/api/system.threading.mutex?view=net-6.0),[`ReaderWriterLock`](https://learn.microsoft.com/en-us/dotnet/api/system.threading.readerwriterlock?view=net-6.0)and many more.

I hope you enjoyed this brief introduction to a very complex topic.

* * *

**P.S. Whenever you're ready, there are 2 ways I can help you:**

1. [**Pragmatic Clean Architecture:**](https://www.milanjovanovic.tech/pragmatic-clean-architecture?utm_source=dev.to&utm_medium=website&utm_campaign=cross-posting) This comprehensive course will teach you the system I use to ship production-ready applications using Clean Architecture. Learn how to apply the best practices of modern software architecture. [**Join 950+ students here.**](https://www.milanjovanovic.tech/pragmatic-clean-architecture?utm_source=dev.to&utm_medium=website&utm_campaign=cross-posting)

2. [**Patreon Community:**](https://www.patreon.com/milanjovanovic) Think like a senior software engineer with **access to the source code** I use in my YouTube videos and **exclusive discounts** for my courses. [**Join 820+ engineers here.**](https://www.patreon.com/milanjovanovic)