Monday, July 22, 2019

How to resolve a deadlock in a multithreaded program

We will discuss, acquiring locks in a specific defined order to resolve a deadlock. We will be working with the same example that we worked with in Part 95

Sample program code used in the demo. 
using System;
using System.Threading;

public class Program
{
    public static void Main()
    {
        Console.WriteLine("Main Started");
        Account accountA = new Account(1015000);
        Account accountB = new Account(1023000);

        AccountManager accountManagerA =
            new AccountManager(accountAaccountB1000);
        Thread T1 = new Thread(accountManagerA.Transfer);
        T1.Name = "T1";

        AccountManager accountManagerB =
            new AccountManager(accountBaccountA2000);
        Thread T2 = new Thread(accountManagerB.Transfer);
        T2.Name = "T2";

        T1.Start();
        T2.Start();

        T1.Join();
        T2.Join();
        Console.WriteLine("Main Completed");
    }
}

public class Account
{
    double _balance;
    int _id;

    public Account(int iddouble balance)
    {
        this._id = id;
        this._balance = balance;
    }

    public int ID
    {
        get
        {
            return _id;
        }
    }

    public void Withdraw(double amount)
    {
        _balance -= amount;
    }

    public void Deposit(double amount)
    {
        _balance += amount;
    }
}

public class AccountManager
{
    Account _fromAccount;
    Account _toAccount;
    double _amountToTransfer;

    public AccountManager(Account fromAccountAccount toAccountdoubleamountToTransfer)
    {
        this._fromAccount = fromAccount;
        this._toAccount = toAccount;
        this._amountToTransfer = amountToTransfer;
    }

    public void Transfer()
    {
        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.ToString());

        lock (_lock1)
        {
            Console.WriteLine(Thread.CurrentThread.Name
                + " acquired lock on "
                + ((Account)_lock1).ID.ToString());

            Console.WriteLine(Thread.CurrentThread.Name
                + " suspended for 1 second");

            Thread.Sleep(1000);
            Console.WriteLine(Thread.CurrentThread.Name
                + " back in action and trying to acquire lock on "
                + ((Account)_lock2).ID.ToString());

            lock (_lock2)
            {
                Console.WriteLine(Thread.CurrentThread.Name
                    + " acquired lock on "
                    + ((Account)_lock2).ID.ToString());

                _fromAccount.Withdraw(_amountToTransfer);
                _toAccount.Deposit(_amountToTransfer);

                Console.WriteLine(Thread.CurrentThread.Name + " Transfered "
                    + _amountToTransfer.ToString() + " from "
                    + _fromAccount.ID.ToString() + " to "
                    + _toAccount.ID.ToString());
            }
        }
    }
}

Deadlock in a multithreaded program

Scenario when a deadlock can occur
Let's say we have 2 threads 
a) Thread 1
b) Thread 2

and 2 resources
a) Resource 1
b) Resource 2

Thread 1 has already acquired a lock on Resource 1 and wants to acquire a lock on Resource 2. At the same time Thread 2 has already acquired a lock on Resource 2 and wants to acquire a lock on Resource 1. Two threads never give up their locks, hence a deadlock. 

Deadlock example 

Example code used in the demo
using System;
using System.Threading;

public class Program
{
    public static void Main()
    {
        Console.WriteLine("Main Started");
        Account accountA = new Account(1015000);
        Account accountB = new Account(1023000);

        AccountManager accountManagerA = new
            AccountManager(accountAaccountB1000);
        Thread T1 = new Thread(accountManagerA.Transfer);
        T1.Name = "T1";

        AccountManager accountManagerB = new
            AccountManager(accountBaccountA2000);
        Thread T2 = new Thread(accountManagerB.Transfer);
        T2.Name = "T2";

        T1.Start();
        T2.Start();

        T1.Join();
        T2.Join();
        Console.WriteLine("Main Completed");
    }
}

public class Account
{
    double _balance;
    int _id;

    public Account(int iddouble balance)
    {
        this._id = id;
        this._balance = balance;
    }

    public int ID
    {
        get
        {
            return _id;
        }
    }

    public void Withdraw(double amount)
    {
        _balance -= amount;
    }

    public void Deposit(double amount)
    {
        _balance += amount;
    }
}

public class AccountManager
{
    Account _fromAccount;
    Account _toAccount;
    double _amountToTransfer;

    public AccountManager(Account fromAccount,
        Account toAccountdouble amountToTransfer)
    {
        this._fromAccount = fromAccount;
        this._toAccount = toAccount;
        this._amountToTransfer = amountToTransfer;
    }

    public void Transfer()
    {
        Console.WriteLine(Thread.CurrentThread.Name
            + " trying to acquire lock on "
            + _fromAccount.ID.ToString());
        lock (_fromAccount)
        {
            Console.WriteLine(Thread.CurrentThread.Name
                + " acquired lock on "
                + _fromAccount.ID.ToString());

            Console.WriteLine(Thread.CurrentThread.Name
                + " suspended for 1 second");

            Thread.Sleep(1000);

            Console.WriteLine(Thread.CurrentThread.Name +
                " back in action and trying to acquire lock on "
                + _toAccount.ID.ToString());

            lock (_toAccount)
            {
                _fromAccount.Withdraw(_amountToTransfer);
                _toAccount.Deposit(_amountToTransfer);
            }
        }
    }
}

Func delegate in c#

What is Func<T, TResult> in C#?
In simple terms, Func<T, TResult> is just a generic delegate. Depending on the requirement, the type parameters (T and TResult) can be replaced with the corresponding type arguments.  

For example, Func<Employeestring> is a delegate that represents a function expecting Employee object as an input parameter and returns a string.

Program used in the demo:
using System;
using System.Collections.Generic;
using System.Linq;

class Program
{
    public static void Main()
    {
        List<Employee> listEmployees = new List<Employee>()
        {
            new EmployeeID = 101Name = "Mark"},
            new EmployeeID = 102Name = "John"},
            new EmployeeID = 103Name = "Mary"},
        };

        // Create a Func delegate
        Func<Employeestring> selector =
            employee => "Name = " + employee.Name;
        // Pass the delegate to the Select() LINQ function
        IEnumerable<string> names = listEmployees.Select(selector);

        // The above output can be achieved using
        // lambda expression as shown below
        // IEnumerable<string> names =
        // listEmployees.Select(employee => "Name = " + employee.Name);

        foreach (string name in names)
        {
            Console.WriteLine(name);
        }
    }

    public class Employee
    {
        public int ID { getset; }
        public string Name { getset; }
    }
}

What is the difference between Func delegate and lambda expression?
They're the same, just two different ways to write the same thing. The lambda syntax is newer, more concise and easy to write.

What if I have to pass two or more input parameters?
As of this recording there are 17 overloaded versions of Func, which enables us to pass variable number and type of input parameters. In the example below, Func<intintstring> represents a function that expects 2 int input parameters and returns a string.

using System;
class Program
{
    public static void Main()
    {
        Func<intintstring> funcDelegate = (firstNumbersecondNumber=>
            "Sum = " + (firstNumber + secondNumber).ToString();

        string result = funcDelegate(1020);
        Console.WriteLine(result);
    }
}

No String Argument Constructor/Factory Method to Deserialize From String Value

  In this short article, we will cover in-depth the   JsonMappingException: no String-argument constructor/factory method to deserialize fro...