using System;
using System.Threading;

namespace ex_050_004_cadenas_et_sécurité
{
    class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("TEST 4 : utilisation d'une seule instance d'une classe utilisant un membre d'instance non protégé");
            Console.WriteLine("2 threads lancent une même méthode d'instance, mais à partir d'une seule instance.");
            Console.WriteLine("Cette méthode affiche la valeur d'un membre d'instance, puis le passe à true s'il vaut false.");
            Console.WriteLine("On lance les 2 threads en même temps, 10 fois de suite.");
            Console.WriteLine("On peut voir ci-dessous que le résultat peut parfois varier :");
            Console.WriteLine("parfois, les deux affichages se font en même temps, avant qu'un des deux threads ait eu le temps de modifier la valeur de instanceTest ;");
            Console.WriteLine("d'autres fois, non.");

            for (int i = 0; i < 10; i++)
            {
                Test test = new Test();
                Thread thread1 = new Thread(test.MéthodeAvecMembreDInstance) { Name = "thread1" };
                Thread thread2 = new Thread(test.MéthodeAvecMembreDInstance) { Name = "thread2" };

                thread1.Start();
                thread2.Start();

                thread1.Join();
                thread2.Join();

                Console.WriteLine();
            }

            Console.WriteLine("Appuyez sur une touche pour tester avec un cadenas");
            Console.ReadLine();

            Console.WriteLine("TEST 4b : utilisation d'une seule instance d'une classe utilisant un membre d'instance protégé par un cadenas.");
            Console.WriteLine("2 threads lancent une même méthode d'instance, mais à partir d'une seule instance.");
            Console.WriteLine("Cette méthode affiche la valeur d'un membre d'instance, puis le passe à true s'il vaut false.");
            Console.WriteLine("On lance les 2 threads en même temps, 10 fois de suite.");
            Console.WriteLine("On peut voir ci-dessous que le résultat ne varie jamais, car l'utilisation du membre d'instance est protégé par un cadenas.");

            for (int i = 0; i < 10; i++)
            {
                TestLock test = new TestLock();
                Thread thread1 = new Thread(test.MéthodeAvecMembreDInstance) { Name = "thread1" };
                Thread thread2 = new Thread(test.MéthodeAvecMembreDInstance) { Name = "thread2" };

                thread1.Start();
                thread2.Start();

                thread1.Join();
                thread2.Join();

                Console.WriteLine();
            }
        }
    }

    class Test
    {
        bool instanceTest = false;

        public void MéthodeAvecMembreDInstance()
        {
            Console.WriteLine("instanceTest ({0}) = {1}", Thread.CurrentThread.Name, instanceTest);
            if (!instanceTest)
            {
                instanceTest = true;
            }
            Thread.Sleep(1200);
        }
    }

    class TestLock
    {
        bool instanceTest = false;

        //le cadenas
        static readonly object mLocker = new object();

        public void MéthodeAvecMembreDInstance()
        {
            lock (mLocker) // on vérouille le cadenas pour éviter que le bloc suivant puisse être exécuté en parallèle
            {
                Console.WriteLine("instanceTest ({0}) = {1}", Thread.CurrentThread.Name, instanceTest);
                if (!instanceTest)
                {
                    instanceTest = true;
                }
            }
            Thread.Sleep(1200);
        }
    }
}
