How to avoid Deadlock in C#

How to avoid Deadlock in C#

In this article, I am going to discuss How to Avoid Deadlock in C# with an example. Please read our previous article before proceeding to this article where we discussed what a deadlock is and why and how a deadlock can occur in a multithreaded application with an example. We are also going to work with the same example that we created in our previous article. We can prevent a deadlock in a multithreaded application by using different approaches. As part of this article, we are going to discuss the following pointers.

  1. How to avoid Deadlock by using Monitor.TryEnter method?
  2. How to avoid Deadlock by acquiring locks in a specific order?
Avoiding Deadlock by using Monitor.TryEnter method?

The second parameter of Monitor.TryEnter method takes time out in milliseconds. Using that parameter we can specify a timeout for the thread to release the lock. If a thread is holding a resource for a long time while the other thread is waiting, then Monitor will provide a time limit and force the lock to release it. So that the other thread will enter into the critical section.

Modifying the AccountManager class as shown below:

using System;
using System.Threading;

namespace DeadLockDemo
{
    public class AccountManager
    {
       private Account FromAccount;
       private Account ToAccount;
       private double TransferAmount;

        public AccountManager(Account AccountFrom, Account AccountTo, double AmountTransfer)
        {
            this.FromAccount = AccountFrom;
            this.ToAccount = AccountTo;
            this.TransferAmount = AmountTransfer;
        }

        public void FundTransfer()
        {
            Console.WriteLine($"{Thread.CurrentThread.Name} trying to acquire lock on {FromAccount.ID}");
            
            lock (FromAccount)
            {
                Console.WriteLine($"{Thread.CurrentThread.Name} acquired lock on {FromAccount.ID}");
                Console.WriteLine($"{Thread.CurrentThread.Name} Doing Some work");
                Thread.Sleep(3000);
                Console.WriteLine($"{Thread.CurrentThread.Name} trying to acquire lock on {ToAccount.ID}");
                
                if (Monitor.TryEnter(ToAccount, 3000))
                {
                    Console.WriteLine($"{Thread.CurrentThread.Name} acquired lock on {ToAccount.ID}");
                    try
                    {
                        FromAccount.WithdrawMoney(TransferAmount);
                        ToAccount.DepositMoney(TransferAmount);
                    }
                    finally
                    {
                        Monitor.Exit(ToAccount);
                    }
                }
                else
                {
                    Console.WriteLine($"{Thread.CurrentThread.Name} Unable to acquire lock on {ToAccount.ID}, So existing.");
                }
            }
        }
    }
}

Output:

How to avoid Deadlock in C# by using Monitor.TryEnter method

As you can see in the output thread1 release the lock and exists from the critical section which allows thread2 to enter the critical section.

How to avoid Deadlock in C# by acquiring locks in a specific order?

Please modify the AccountManager class as shown below.

using System;
using System.Threading;

namespace DeadLockDemo
{
    public class AccountManager
    {
       private Account FromAccount;
       private Account ToAccount;
       private readonly double TransferAmount;
       private static readonly Mutex mutex = new Mutex();

        public AccountManager(Account AccountFrom, Account AccountTo, double AmountTransfer)
        {
            this.FromAccount = AccountFrom;
            this.ToAccount = AccountTo;
            this.TransferAmount = AmountTransfer;
        }

        public void FundTransfer()
        {
            object _lock1, _lock2;

            if (FromAccount.ID < ToAccount.ID)
            {
                _lock1 = FromAccount;
                _lock2 = ToAccount;
            }
            else
            {
                _lock1 = ToAccount;
                _lock2 = FromAccount;
            }

            Console.WriteLine($"{Thread.CurrentThread.Name} trying to acquire lock on {((Account)_lock1).ID}");
            
            lock (_lock1)
            {
                Console.WriteLine($"{Thread.CurrentThread.Name} acquired lock on {((Account)_lock1).ID}");
                Console.WriteLine($"{Thread.CurrentThread.Name} Doing Some work");
                Thread.Sleep(3000);
                Console.WriteLine($"{Thread.CurrentThread.Name} trying to acquire lock on {((Account)_lock2).ID}");
                lock(_lock2)
                {
                    Console.WriteLine($"{Thread.CurrentThread.Name} acquired lock on {((Account)_lock2).ID}");
                    FromAccount.WithdrawMoney(TransferAmount);
                    ToAccount.DepositMoney(TransferAmount);
                }
            }
        }
    }
}

Output:

How to avoid Deadlock in C# by acquiring locks in a specific order

That’s it for today. In the next article, I am going to show you the Performance of a multithreaded program when running on a single core/processor machine versus the multi-core/processor machine. Here, in this article, I try to explain how to avoid deadlock in multithreaded application with different approaches.

1 thought on “How to avoid Deadlock in C#”

  1. making more confusion while executing the program, if we put some amount more than balance available in it while withdraw it is accepting

Leave a Reply

Your email address will not be published. Required fields are marked *