igritco
5/13/2018 - 10:08 AM

Exam 70-483

Personal notes on training for Exam 70-483

// delegates are a reference to a functiona
        public delegate int Calculate(int a, int b);

        public static int Add(int a, int b)
        {
            return a + b;
        }

        public static int Multiply(int a, int b)
        {
            return a * b;
        }

        static void Main(string[] args)
        {
            Calculate calc = Add;
            
            Console.WriteLine(calc(1, 2));
        }
        
// you can subscride more methods to the same delegate and when the delegate will be called, all the subscribers will be called
public void MultiCast()
        {
            Calculate calc = Add;
            calc += Multiply;

            var x = calc(1, 2);

            Console.WriteLine(x);
        }
// you can use anonymous lambda expressions instead of creating separate methods
        public delegate int Calculate(int x, int y);
        public MultipleCast()
        {
            Calculate calc = (int x, int y) => x + y;
        }

// we can use also events in case we want to fire made an action when the event is fired, in this case when the value of speed is greater than 60
class Program
    {
        static void Main(string[] args)
        {
            Car c = new Car();
            c.OnChange += C_OnChange;

            c.Speed = 50;
            c.Speed = 70;
            Console.ReadLine();
        }

        private static void C_OnChange()
        {
            Console.WriteLine("Event is fired. Car speed >60");
        }
    }

    class Car
    {
        public event Action OnChange;

        private double speed;

        public double Speed
        {
            get { return speed; }
            set
            {
                speed = value;
                if (speed >= 60)
                {
                    if (OnChange != null)
                    {
                        OnChange();
                    }
                }

            }
        }
    }
using System;
using System.Threading;

namespace ConsoleApp1
{
    class Program
    {
        public static void ThreadMethod()
        {
            for (int i = 0; i < 10; i++)
            {
                Console.WriteLine($"ThreadMethod {i}");
                Thread.Sleep(0);
            }
        }

        static void Main(string[] args)
        {
            Thread t = new Thread(new ThreadStart(ThreadMethod));
            t.Start();

            for (int i = 0; i < 4; i++)
            {
                Console.WriteLine($"MainThread {i}");
                Thread.Sleep(0);
            }

            t.Join();
        }
    }
}

//Thread.Sleep(0) - elibereaza threadul si in caz ca exista un thread cu o prioritate mai mare, ala va porni 
//(It means that you will allow other processes to run their code, but also try to continue your own code as soon as possible.)
//t.Join - main thread will wait for the t thread in order to continue the main process - example with console.writeline("after") after the join - if we have join it'll print immediatelly, otherwise it'll print just after the second thread finished
 static void Main(string[] args)
        {
            Thread t = new Thread(new ThreadStart(ThreadMethod));
            t.IsBackground = true;
            t.Start();
        }
//t.IsBackground - threadul o sa ruleze in background si in cazul unei console nu va afisa nimic in interfata
//by default t.IsBackground e false

 public static void ThreadMethod(object o)
        {
            for (int i = 0; i < (int)o; i++)
            {
                Console.WriteLine($"ThreadMethod {i}");
                Thread.Sleep(0);
            }
        }
////
Thread t = new Thread(new ParametrizedThreadStart(ThreadMethod));
t.Start(5);

// parametrized thread

        static void Main(string[] args)
        {
            bool stopped = false;


            Thread t = new Thread(new ThreadStart(()=> {
                while (!stopped)
                {
                    Console.WriteLine("Running ...");
                    Thread.Sleep(1000);
                }
            }));
            t.Start();


            Console.WriteLine("Press any key to exit");

            Console.ReadKey();
            stopped = true;
            t.Join();
        }
        
// in case we need variables that are visible in multiple thread we can use lamba functions when creating a new thread
// in this case for example, when the user will press any key, the stopped variable will become false and the loop from the second thread will stop

        [ThreadStatic]
        public static int field;

        static void Main(string[] args)
        {
            Thread t1 = new Thread(new ThreadStart(() => {
                for (int i = 0; i < 10; i++)
                {
                    field++;
                    Console.WriteLine($"Thread 1 {field}");
                }
            }));
            t1.Start();

            Thread t2 = new Thread(new ThreadStart(() => {
                for (int i = 0; i < 10; i++)
                {
                    field++;
                    Console.WriteLine($"Thread 2 {field}");
                }
            }));
            t2.Start();
        }

//[TreadStatic] asigura faptul ca o proprietate, chiar daca e globala, va avea valoarea ei separata in fiecare thread
// in exemplul de mai sus vom avea de doua ore in consola Thread 1 pana la 10 si Thread 2 pana la 10
// daca am scoate ThreadStatic atunci al doilea thread va incrementa valoarea pana la 20 si nu va incepe de la 0


//TreadPool - managed thread instances. You cannot see when the action is finished or the result of the thread
//Task are using ThreadPool and you can see the return value of the thread
Task t = Task.Run(() => {
                for (int i = 0; i < 100; i++)
                {
                    Console.Write("*");
                }
            });
t.Wait();
//t.Wait is equal with thread.Join - waits until moving forward with the actions
// if we have a task that return an result like Task<int> t = Task.Run(()=> {return 72;});
// when we'll get the result with t.Result, it'll automatically do a t.Wait() in background, so we don't need to specify it

Task<int> t = Task.Run(() =>
            {
                return 72;
            }).ContinueWith((i) =>
            {
                return i.Result * 2;
            });
// ContinueWIth will work similar with t.Result and will first finish the first task and after this will go to the next one

 Task<int> t = Task.Run(() =>
            {
                return 2;
            }).ContinueWith((i) =>
            {
                return i.Result * 2;
            });

            t.ContinueWith((i) =>
            {
                return i.Result * 2;
            });
            
            console.writeline(t.result);
// The result of this statement will be 4 and not 8 because it'll take just the first part since we're using the t.Result
// in case we want it also in this case, the code should reasing t to the continuation like
t = t.ContinueWith((i) =>
            {
                return i.Result * 2;
            });

// Continue with can be runned on specific cases, for example only whtn there is an error in the previous task
.ContinueWith((i) =>
            {
                Console.WriteLine("Faulted");

            }, TaskContinuationOptions.OnlyOnFaulted);
//Task.WaitAll(arrayOfTask) - will wait until all the tasks from the array parameter are finished
//Task.WaitAny(arrayOfTask) - will wait until first task will finish from the array parameter of tasks

// Parrallel.For and Parralel.ForEach are using task, so this means they are using ThreadPool
// they should be used in cases when you need to parallelize actions for a list where an action is independent of all other element list
// we don't know the order for Parralel.For and Parralel.ForEach since they are running in parralel
// This means that we should not expect to run from 1 to 10 like an usual for, because it'll not run in order

public static async Task<string> DownloadContent()
        {
            using (HttpClient client = new HttpClient())
            {
                string result = await client.GetStringAsync("http://www.microsoft.com");

                return result;
            }
        }

        static void Main(string[] args)
        {
            string result = DownloadContent().Result;
            Console.WriteLine(result);
        }
// await here is equal to adding client.GetStringAsync("dsadsa").Result, so it'll wait until the action will be done and will transform the result in desired type
// async or await are not creating any task, they just mark the method/actions as asyncron

-----
// lock it's used to block concurent thread to use the same resources
int n = 0;
            object locked = new object();
            Task myTask = Task.Run(() => {
                for (int i = 0; i < 1000000; i++)
                {
                    lock (locked)
                    {
                        n++;
                    }
                }
            });

            for (int i = 0; i < 1000000; i++)
            {
                lock (locked)
                {
                    n--;
                }
            }

            myTask.Wait();
            Console.WriteLine(n);
// if we'll use the previous example, the result will be always 0
// instead, if we'll remove the lock, the result will be unpredictable, because we have a read and write action and they can be in the same time read/write by multiple threads
// for example we have n=n+1 - when we read the value it's 4. Meantime the value was updated to 5 by other thread and when we write the value instead of having 6, we'll write again 5, because when we read the value it was 4

object locked1 = new object();
            object locked2 = new object();
            Task myTask = Task.Run(() =>
            {
                lock (locked1)
                {
                    lock (locked2)
                    {
                        Console.WriteLine("Locked A and B");
                    }
                }
            });

            lock (locked2)
            {
                Thread.Sleep(1000);
                lock (locked1)
                {
                    Console.WriteLine("Locked B and A");
                }
            }
// this is an example of a DEADLOCK
// what happens here is that on lock on a thread is waiting for the same lock on a different thread and this nevers ends since they are waiting one for another
// for the previous example, the main thread is waiting to the locked1 to be released and the second thread is waiting for locked2 to be released

            int n = 0;
            Task myTask = Task.Run(() =>
            {
                for (int i = 0; i < 1000000; i++)
                {
                    Interlocked.Increment(ref n);
                }
            });

            for (int i = 0; i < 1000000; i++)
            {
                Interlocked.Decrement(ref n);
            }

            myTask.Wait();
            Console.WriteLine(n);
// As an alternative to lock, we can use atomic operation using Interlocked.Increment/Decrement (atomic - thread safe)

            CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
            CancellationToken cancellationToken = cancellationTokenSource.Token;
            Task myTask = Task.Run(() =>
            {
                while (!cancellationToken.IsCancellationRequested)
                {
                    Console.Write("*");
                    Thread.Sleep(1000);
                }
            }, cancellationToken);

            Console.WriteLine("Press enter to stop the task");
            Console.ReadLine();

            cancellationTokenSource.Cancel();

            Console.WriteLine("Please enter to stop the program");
            Console.ReadLine();
// the example above show how you can create a cancelation token and how can you stop a task

 CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
            CancellationToken cancellationToken = cancellationTokenSource.Token;
            Task myTask = Task.Run(() =>
            {
                while (!cancellationToken.IsCancellationRequested)
                {
                    Console.Write("*");
                    Thread.Sleep(1000);
                }

                cancellationToken.ThrowIfCancellationRequested();
            }, cancellationToken);

            try
            {
                Console.WriteLine("Press enter to stop the task");
                Console.ReadLine();

                cancellationTokenSource.Cancel();
                myTask.Wait();
            }
            catch (AggregateException ex)
            {
                Console.WriteLine(ex.InnerExceptions[0].Message);
            }
            

            Console.WriteLine("Please enter to stop the program");
            Console.ReadLine();
// this example shows how you can throw exceptions in case the task was terminated

            Task myTask = Task.Run(() =>
            {
                Thread.Sleep(5000);
            });

            int index = Task.WaitAny(new[] { myTask }, 1000);
            if (index == -1)
            {
                Console.WriteLine("Timeout");
            }
// this example show how you can set a timeout for a task

// Action<int, int> Calculate is equal to public delagate void Calculate(int x, int y)
// Action and Func are predefined delegates - Action returns void, Func returns an object