Monday, 30 December 2019

C# - Thread Volatile

Two separate thread. First thread is default main program thread and the second one is child thread which we started by initiate a new Thread instance in our code.
Update CheckStatus as false in our main method, thread update their local variable value and Sync that into main memory location. The problem is the CheckStatus in the child thread are not updated in their local memory accordingly.
We can understand when we work with multiple threads, all threads have their own local memory and any update in local memory sync with main memory but that will be not reflected in other threads local memory. So, when multiple thread working on common variables it will create problem. 
*Use volatile Keyword to Fix Problems With Reading/Writing Shared Data.

Microsoft Doc

The volatile keyword indicates that a field might be modified by multiple threads that are executing at the same time. The compiler, the runtime system, and even hardware may rearrange reads and writes to memory locations for performance reasons. Fields that are declared volatile are not subject to these optimizations. Adding the volatile modifier ensures that all threads will observe volatile writes performed by any other thread in the order in which they were performed. There is no guarantee of a single total ordering of volatile writes as seen from all threads of execution.


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Volatile
{
    public class MainThreadProgram
    {
        volatile bool CheckStatus = true;
        static void Main(string[] args)
        {
            MainThreadProgram mainthread = new MainThreadProgram();
            Thread childThread = new Thread(() => ChildThread(mainthread));
            childThread.Start();
            Thread.Sleep(5000);
            mainthread.CheckStatus = false;
            Console.WriteLine("Change CheckStatus false");
        }

        private static void ChildThread(MainThreadProgram objProgram)
        {
            Console.WriteLine("Child Thread Loop Starting...");
            while (objProgram.CheckStatus)
            {
            }
            Console.WriteLine("Child Thread Loop Stopping...");
        }

    }
}

Sunday, 29 December 2019

C# - Thread Semaphore


Limits the number of threads that can access a resource or pool of resources concurrently.


using System;
using System.Threading;

namespace Program
{
    class Demo
    {
        static Thread[] t = new Thread[5];
        static Semaphore semaphore = new Semaphore(2, 2);
        static void DoSomething()
        {
            Console.WriteLine("{0} = waiting", Thread.CurrentThread.Name);
            semaphore.WaitOne();
            Console.WriteLine("{0} begins!", Thread.CurrentThread.Name);
            Thread.Sleep(1000);
            Console.WriteLine("{0} releasing...", Thread.CurrentThread.Name);
            semaphore.Release();
        }
        static void Main(string[] args)
        {
            for (int j = 0; j < 5; j++)
            {
                t[j] = new Thread(DoSomething);
                t[j].Name = "thread number " + j;
                t[j].Start();
            }
            Console.Read();
        }
    }
}



C# - Thread Lock


Simple Example 1


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ThreadLock
{
    class Program
    {
        static readonly object lockobject = new object();

        static void PrintInfo()
        {
            lock (lockobject)
            {
                for (int i = 1; i <= 4; i++)
                {
                    Console.WriteLine("i value: {0}", i);
                    Thread.Sleep(1000);
                }
            }
        }

        static void Main(string[] args)
        {
            Thread t1 = new Thread(new ThreadStart(PrintInfo));
            Thread t2 = new Thread(new ThreadStart(PrintInfo));
            t1.Start();
            t2.Start();
            Console.ReadLine();
        }
    }
}



MSDN

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Bank
{   
    public class Account
    {
        private readonly object balanceLock = new object();
        private decimal balance;

        public Account(decimal initialBalance)
        {
            balance = initialBalance;
        }

        public decimal Debit(decimal amount)
        {
            lock (balanceLock)
            {
                if (balance >= amount)
                {
                    Console.WriteLine($"Balance before debit :{balance,5}");
                    Console.WriteLine($"Amount to remove     :{amount,5}");
                    balance = balance - amount;
                    Console.WriteLine($"Balance after debit  :{balance,5}");
                    return amount;
                }
                else
                {
                    return 0;
                }
            }
        }

        public void Credit(decimal amount)
        {
            lock (balanceLock)
            {
                Console.WriteLine($"Balance before credit:{balance,5}");
                Console.WriteLine($"Amount to add        :{amount,5}");
                balance = balance + amount;
                Console.WriteLine($"Balance after credit :{balance,5}");
            }
        }
    }

    class AccountTest
    {
        static void Main()
        {
            var account = new Account(1000);
            var tasks = new Task[100];
            for (int i = 0; i < tasks.Length; i++)
            {
                tasks[i] = Task.Run(() => RandomlyUpdate(account));
            }
            Task.WaitAll(tasks);
        }

        static void RandomlyUpdate(Account account)
        {
            var rnd = new Random();
            for (int i = 0; i < 10; i++)
            {
                var amount = rnd.Next(1, 100);
                bool doCredit = rnd.NextDouble() < 0.5;
                if (doCredit)
                {
                    account.Credit(amount);
                }
                else
                {
                    account.Debit(amount);
                }
            }
        }
    }
}
 

C# Multithreading


using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace Multithreading
{
    class Program
    {
        static void Main(string[] args)
        {
            // Create child threads
            Thread t1 = new Thread(new ThreadStart(Task1));
            Thread t2 = new Thread(new ThreadStart(Task2));

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

            Console.ReadLine();
        }

        static void Task1()
        {
            for (int i = 1; i <= 4; i++)
            {
                Console.WriteLine("First Thread - value: {0}", i);

                Thread.Sleep(1000);
            }

            Console.WriteLine("First method completed");
        }

        static void Task2()
        {
            for (int i = 1; i <= 4; i++)
            {
                Console.WriteLine("Second Thread - value: {0}", i);
            }

            Console.WriteLine("Second method completed");
        }
    }
}