c-sharp
  1. c-sharp-synchronization

C# Synchronization

Synchronization in C# refers to the coordination of multiple threads to ensure that they access shared resources in a safe and orderly manner. In multi-threaded applications, it's important to ensure that multiple threads don't access shared resources at the same time, which could result in memory corruption or incorrect results. In this tutorial, we'll discuss how to use synchronization in C#.

Syntax

In C#, there are several ways to synchronize access to shared resources, including:

  • Lock statement
  • Mutex
  • Semaphore
  • ReaderWriterLock

Here's an example of using a lock statement to synchronize access to a shared resource:

object lockObject = new object();
int sharedResource = 0;

public void IncrementResource() {
   lock (lockObject) {
      sharedResource++;
   }
}

The lock statement is used to obtain a lock on the lockObject, ensuring that only one thread can access the shared resource at a time.

Example

Let's say we want to create a class that represents a bank account with a balance. Multiple threads may attempt to deposit or withdraw from the account simultaneously, so we need to use synchronization to ensure the balance is updated correctly. Here's how we can implement it using a lock statement:

public class BankAccount {
   private object lockObject = new object();
   private decimal balance;

   public decimal Balance {
      get { return balance; }
   }

   public void Deposit(decimal amount) {
      lock (lockObject) {
         balance += amount;
      }
   }

   public void Withdraw(decimal amount) {
      lock (lockObject) {
         if (balance >= amount) {
            balance -= amount;
         }
      }
   }
}

Now, we can create multiple threads that deposit and withdraw from the account:

BankAccount account = new BankAccount();
Thread t1 = new Thread(new ThreadStart(() => account.Deposit(100)));
Thread t2 = new Thread(new ThreadStart(() => account.Withdraw(50)));

t1.Start();
t2.Start();

t1.Join();
t2.Join();

Console.WriteLine(account.Balance); // Output: 50

Output

When we run the example code above, the output will be:

50

This is because we deposited 100 and withdrew 50, resulting in a final balance of 50.

Explanation

In the example above, we created a BankAccount class with a balance field. We implemented Deposit and Withdraw methods, both of which use a lock statement to synchronize access to the balance field. This ensures that only one thread can access the balance field at a time, preventing race conditions and incorrect results.

We then created two threads that deposit and withdraw from the account, respectively. Finally, we printed the final balance to the console.

Use

Synchronization is important in multi-threaded scenarios to ensure that multiple threads don't access shared resources simultaneously, resulting in race conditions, memory corruption, or incorrect results. You should use synchronization whenever you have multiple threads accessing shared resources.

Important Points

  • Synchronization should be used to prevent race conditions and ensure that multiple threads don't access shared resources simultaneously.
  • Different synchronization mechanisms have different performance characteristics and trade-offs, so choose the one that fits your scenario best.
  • When using a lock statement, always use the same lock object to ensure that two threads don't inadvertently lock on different objects, which would result in deadlock.

Summary

In this tutorial, we discussed how to use synchronization in C# to ensure that multiple threads don't access shared resources simultaneously. We covered the syntax, example, output, explanation, use, and important points of synchronization in C#. With this knowledge, you can now use synchronization to prevent race conditions and ensure the correctness of your multi-threaded applications.

Published on: