domenica 2 ottobre 2011

How To: Use Mutex and Thread C#

In più di un occasione mi sono imbattutto nell'annosa situazione di dover riempire una lista con dati che provengono da fonti differenti.

Per risolvere questa situazione ci possono essere davvero molti molti prototipi, tuttavia ogni programmatore ha diritto di scegliere che cosa utilizzare.

Il problema di fondo e che accedere in modo concorrenziale a chi dovrà contenere
i dati potrebbe generalmente essere causa di sovrascritture .. o affini.

In questo esempio utilizzo il Mutex, anche se onestamente ritengo molto più edificante utilizzare il lock.


L'esempio pratico.

public class simpleEntity
{
#region Private Properties
private int _id_simpleEntity = 0;
private string _CreationDate ="";
private string _ThreadOwner ="";
#endregion

#region Public Properties
public int id_simpleEntity
{
get { return _id_simpleEntity; }
set { _id_simpleEntity = value; }
}

public string CreationDate
{
get { return _CreationDate; }
set { _CreationDate = value; }
}

public string ThreadOwner
{
get { return _ThreadOwner; }
set { _ThreadOwner = value; }
}
#endregion
}


La mia "solita entity"..

public class simpleEntityList:List<simpleEntity>
{
Mutex _mtx = new Mutex();

public void AddEntity(simpleEntity se)
{
_mtx.WaitOne();
this.Add(se);
_mtx.ReleaseMutex();
}

public void RemoveEntity(int idx)
{
_mtx.WaitOne();
this.RemoveAt(idx);
_mtx.ReleaseMutex();
}

public int CountEntity()
{
int j = 0;
_mtx.WaitOne();
j = this.Count;
_mtx.ReleaseMutex();
return j;
}
}


Questa è la collection, che tuttavia non è proprio la solita.
Non è difficile notare la presenza del Mutex sugli metodi principali.

public class _threadParameters
{
public int _maxEntity;
public string _owner;
public simpleEntityList _sel;
}


Il mio state object.


public class simpleEntityCreator
{

Mutex _mtx = new Mutex();
public void buildEntity(object lthp)
{
_threadParameters thp = (_threadParameters)lthp;
int startID = Program._sx.CountEntity() +1;

for (int i = 0; i < thp._maxEntity; i++)
{
simpleEntity se = new simpleEntity();
se.id_simpleEntity = startID + i;
se.ThreadOwner = thp._owner;
se.CreationDate = DateTime.Now.ToLongTimeString();
//Program._sx.AddEntity(se);
thp._sel.AddEntity(se);
}

_mtx.WaitOne();
Console.WriteLine("***********************************************");
Console.WriteLine(thp._owner +" ha finito ");
for (int i = 0; i < Program._sx.Count; i++)
{
if (Program._sx[i].ThreadOwner == thp._owner)
Console.WriteLine(" id : " + Program._sx[i].id_simpleEntity.ToString() + "|" +
Program._sx[i].ThreadOwner.ToString() + "|" + Program._sx[i].CreationDate);
}
Console.WriteLine("***********************************************");
_mtx.ReleaseMutex();
}

}


Questa classe si preoccupa di Riempire la lista... e di scrivere che cosa sta
combinando ( come se fosse un Trace... )


class Program
{

public static simpleEntityList _sx = new simpleEntityList();
static void Main(string[] args)
{
Console.WriteLine("Main Start");
Console.ReadLine();


_threadParameters tph1 = new _threadParameters();
_threadParameters tph2 = new _threadParameters();
tph1._sel = _sx;
tph2._sel = _sx;


simpleEntityCreator _sec = new simpleEntityCreator();

Thread tFiller1 = new Thread(
new ParameterizedThreadStart(_sec.buildEntity));
tph1._maxEntity = 20;
tph1._owner = "t1";
tFiller1.Start(tph1);


Thread tFiller2 = new Thread(
new ParameterizedThreadStart(_sec.buildEntity));

tph2._maxEntity = 35;
tph2._owner = "t2";
tFiller2.Start(tph2);

Console.WriteLine("Main End");
Console.ReadLine();
}


}



E questo è il main ....

Per comprendere bene che cosa avvine l'unica è provarlo... anche se in debug, non è sempre comprensibile ( dato che si tratta di due thread distinti ) quale è in azione.

Nessun commento: