martedì 26 marzo 2013

Sincronizzazione

Sull'argomento ci sono svariati modelli di implementazione e di contro anche svariati algoritmi più o meno complessi in base anche al tipo di sincronizzazione che vogliamo
effettuare. In molti casi questo tipo di pratica può essere banalmente svolta tramite uno script dos schedulato, tuttavia non si ha il pieno controllo della struttura.

Quello che mi serve e quello che rappresenterò non è altro che un sottoinsieme della mia reale necessità, e più schematicamente è rappresentabile secondo quanto segue:
a) Monitoraggio continuo,
b) Copia specifica di cartelle / file
c) Esecuzione di attività server side propedeutiche alla sincronizzazione.
d) Log delle attività
e) bassa o assente iterazione utente

A fronte di questi brevi requisiti, non è difficile intuire che il tutto sarà reso tramite un servizio, depositato sulla macchina che chiameremo host B. La macchina host A
potrebbe essere interpretata come il pc o device con i sorgenti.




A fronte di questi brevi requisiti, non è difficile intuire che il tutto sarà reso tramite un servizio, depositato sulla macchina che chiameremo host B. La macchina host A
potrebbe essere interpretata come il pc o device con i sorgenti.


Ciò detto l'atto in se della sincronizzazione è rappresentato con un banale File.Copy, il più e comprendere come e cosa copiare.


public partial class beeSyncro : ServiceBase
{
    FileSystemWatcher fsw;

    string deployM = @"C:\Users\f.arosio\Deploy_Master";
    string deployS = @"C:\Users\f.arosio\Deploy_Slave";

    string dLog = @"C:\Users\f.arosio\LogFile";

    public beeSyncro()
    {
        InitializeComponent();
        
    }

    protected override void OnStart(string[] args)
    {
        fsw = new FileSystemWatcher();

        fsw.Path = deployM;
        fsw.Filter = "*.dll";
        fsw.IncludeSubdirectories = true;
        fsw.NotifyFilter = NotifyFilters.FileName |
                NotifyFilters.LastWrite | 
                NotifyFilters.CreationTime | 
                NotifyFilters.Size;

        fsw.Created += new FileSystemEventHandler(
                fsw_Created
                );
                        
        fsw.EnableRaisingEvents = true;
        DoWirteLog("Start");
    }

    void fsw_Created(object sender, FileSystemEventArgs e)
    {
        DoWirteLog("Now Copy :" +e.FullPath);
        try
        {
            File.Copy(deployM + @"\" + e.Name, 
            deployS + @"\" + e.Name,true);
        }
        catch (Exception ex)
        {
            DoWirteLog("Copy Failed:" 
            + e.FullPath +" " + 
            ex.Message.ToString().Replace("\r\n",""));
        }
    }

    protected override void OnStop()
    {
        fsw = null;
        DoWirteLog("Stop");
    }

    protected void DoWirteLog(string message)
    {
        TextWriter tw = new StreamWriter(dLog
            +@"\log.log",true);

        tw.WriteLine(DateTime.Now.ToShortDateString() 
            +"|" +DateTime.Now.ToLongTimeString() 
            +"|"+ message);
        tw.Close();
        tw = null;        
    }               
} 
In breve questo è il sorgente che rappresenta il nostro "caso".  Il punto di interesse è dato proprio del FileSystemWatcher, che di suo riesce notificare l'avvenuto cambiamento di una risorsa senza consumeare eccessive risorse di sistema Naturalmente non si sta faecendo ragionamento alcuno su quali file è necessario&nbsp
void fsw_Created(object sender, FileSystemEventArgs e)
{
    DoWirteLog("Now Copy :" +e.FullPath);
    try
    {
        File.Copy(deployM + @"\" + e.Name, 
        deployS + @"\" + e.Name,true);
    }
    catch (Exception ex)
    {
        DoWirteLog("Copy Failed:" 
        + e.FullPath +" " + 
        ex.Message.ToString().Replace("\r\n",""));
    }
}
Questo è il punto , dove possiamo inserire la nostra logica nel caso "si avesse" la necessità di aggiungere granularità al nostro "ben misero Algoritmo".

lunedì 25 marzo 2013

Aree Condivise e Lock ( parte 2)

Diciamo pure che la sto mettendo sul lato personale...

    class Program
    {
        static void Main(string[] args)
        {
            ConsoleColor[] cx = new ConsoleColor[3];
            Thread[] tx = new Thread[3];

            cx[0] = ConsoleColor.Red;
            cx[1] = ConsoleColor.Yellow;
            cx[2] = ConsoleColor.Green;

            for (int i = 0; i < 3; i++)
            {
                LongWayToVictory tM = new LongWayToVictory(cx[i],
                        "T" + i.ToString().PadLeft(3, '0') + "  ");
                Thread t = new Thread(tM.DoMethod);

                Thread.Sleep(50);
                t.Start();
                tx[i] = t;
            }

            for (int i = 0; i < 3; i++)
            {
                tx[i].Join();
            }

            Console.WriteLine("--------------------------------------------");
            Console.ReadKey();

        }
    }


Mi sono rivisto il codice, e ho cercato di ovviare a eventuli problemi tuttavia l'unica cosa che forse non andava del tutto bene era proprio il look ..

Comunque ho provato ad aggiungere una thread.sleep prima di "startare" il thread che ora assume l'aspetto:

    public class LongWayToVictory
    {
        private ConsoleColor _cc;
        private string _msg = "";

        public LongWayToVictory(ConsoleColor cc, string msg)
        {
            _cc = cc;
            _msg = msg;
        }

        public void DoMethod()
        {
            Write(_msg + " Start " + _cc.ToString());
            Thread.Sleep(3000);
            for (int i = 0; i < 25; i++)
            {
                Write(_msg + " In loop i[" + i.ToString() + "]" +
                            _cc.ToString());
            }

            Write(_msg + " End " + _cc.ToString());
        }

        private void Write(string WhatIWrite)
        {
            object t = new object();
            lock (t)
            {
                Console.ForegroundColor = _cc;
                Console.WriteLine(WhatIWrite);
            }
        }
    }


Sicuramente migliore del precedente... il risultato in questo caso è ottimo ottengo i miei bei colori, ma rimane il dubbio che pur avendo messo una lock e pur avendo specificato il colore con cui deve lavorare la console, ottengo una irrimediabile tolleranza d'errore.

Per altro osservando il codice il comportamento non è del tutto sismile al mio "annoso" caso.

Continuo a lavorarci...

Aree Condivise e Lock

In questi giorni, mi sta facendo impazzire un argomento che dovrebbe essere lineare eppure sembra non essere così.. mi è complesso capire perchè ( non è complesso si tratta di retorica come nella buona parte dei casi).

L'idea è quella di simulare un area comune per differenti thread, e di comprendere come questa debba essere gestita da ogni singolo thread.

Naturalmente l'esempio che riporto è molto lontano dal problema reale, ma abbastanza vicino come "comportamento".

Questa è la mia classe main

    class Program
    {
        static void Main(string[] args)
        {
            ConsoleColor[] cx = new ConsoleColor[3];
            Thread[] tx = new Thread[3];

            cx[0] = ConsoleColor.Red;
            cx[1] = ConsoleColor.Yellow;
            cx[2] = ConsoleColor.Green;

            for (int i = 0; i < 3; i++)
            {
                TestMe tM = new TestMe(cx[i], 
                        "T"+i.ToString().PadLeft(3,'0')+" No lock");
                Thread t = new Thread(tM.DoNolock);

                t.Start();
                tx[i] = t;
            }

            for (int i = 0; i < 3; i++)
            {
                tx[i].Join();
            }

            Console.WriteLine("--------------------------------------------");
            Console.ReadKey();
           

            for (int i = 0; i < 3; i++)
            {
                TestMe tM = new TestMe(cx[i], 
                        "T" + i.ToString().PadLeft(3, '0') + " Look");
                Thread t = new Thread(tM.DoLock);
                t.Start();

                tx[i] = t;
            }

            for (int i = 0; i < 3; i++)
            {
                tx[i].Join();
            }

            Console.WriteLine("--------------------------------------------");
            Console.ReadKey();



            for (int i = 0; i < 3; i++)
            {
                TestMeLock tM = new TestMeLock(cx[i], 
                    "T" + i.ToString().PadLeft(3, '0') + " New class Look");
                Thread t = new Thread(tM.DoWrite);
                t.Start();

                tx[i] = t;
            }

            for (int i = 0; i < 3; i++)
            {
                tx[i].Join();
            }

            Console.WriteLine("--------------------------------------------");
            Console.ReadKey();
        }
    }


Questo le mie due classi di test
La prima

    public class TestMeLock
    {
        private ConsoleColor _cc;
        private string _msg = "";

        public TestMeLock(ConsoleColor cc, string msg)
        {
            object t = new object();
            lock (t)
            {
                _cc = cc;
                _msg = msg;
            }
        }

        public void DoWrite()
        {
            Console.ForegroundColor = _cc;
            Console.WriteLine("Start:" + _msg);
            Thread.Sleep(3000);
            Console.ForegroundColor = _cc;
            Console.WriteLine("Done :" + _msg);

        }

    }


La seconda ...

    public class TestMe
    {
        private ConsoleColor _cc;
        private string _msg = "";

        public TestMe(ConsoleColor cc, string msg)
        {
            _cc = cc;
            _msg = msg;
        }
        
        public void DoNolock()
        {
            Console.ForegroundColor = _cc;
            Console.WriteLine("Start:" + _msg);
            Thread.Sleep(3000);
            Console.ForegroundColor = _cc;
            Console.WriteLine("Done :" + _msg);
            
        }

        public void DoLock()
        {
            object t = new object();

            lock (t)
            {
                Console.ForegroundColor = _cc;
                Console.WriteLine("Start:" + _msg);
                Thread.Sleep(3000);
                Console.ForegroundColor = _cc;
                Console.WriteLine("Done :" + _msg);
               
            }
        }
    }


e questo è l'output...



Nel primo caso mi attendevo un risultato simile.. ma nel secondo e nel terzo onestamente no...
Eppure mi pare di comprendere che il concetto di area comune, si possa gestire meglio che con una lock ... ( che per altro ho scritto come LOOK perchè del resto sono alla moda ) ...

Il mio scopo è quindi comprendere perchè questa sovrapposizione si verifica del resto mi pare evidente che ogni singolo thread abbia le sue variabili, e che la console sia correttamente sollecitata, eppure i colori non tornano.

Ci lavoro un po' su e vi farò sapere.