Mutex vs Semaphore

El otro día estaba leyendo y encontré un sitio que exponía algunas preguntas que hacía Google en su entrevista de trabajo y ví una de ellas y me pareció curiosa (sobre todo porque creía saber la respuesta) y era “¿Diferencia entre Mutex y Semaphore?” y como ahora estoy a ver si aprendo un poco de concurrencia y esas cosicas me dije, esta es fácil a ver si soy capaz de explicarla de una forma sencilla.

 

Lo primero decir es que tanto el Mutex como el Semaphore son herramientas para controlar/bloquear (el nombre correcto es sincronizar, pero vamos…) el acceso a recursos desde nuestros hilillos. Y creo que lo mejor es contar un ejemplo y no de código.

 

Imaginemos (o supongamos) que tenemos 3 cajas que queremos utilizar, cuando una persona viene a utilizar una caja, se la lleva y entonces sólo quedan 2 cajas, cuando ha terminado de utilizarla la deja y vuelven a quedar 3 cajas, si vienen 3 personas y cogen las 3 cajas, el próximo que venga tendrá que esperar a que alguna de las personas termine con la caja y la devuelva.

 

Buenos si a eso le ponemos que las cajas son recursos y las personas son hilos, eso sería, más o menos, el funcionamiento de un Semaphore con Count = 3.

 

Creo que es bastante sencilo, y bien la pregunta ¿qué es el Mutex?, pues la respuestas sencilla sería decir que un Mutex es un Semaphore con Count = 1.

 

Y listo, evidentemente esto es algo más complejo pero creo que eso sería una descripción bastante sencilla y aproximada.

 

Os dejo las direcciones de la documentación del msdn para que veáis ejemplos, aquí el Mutex y aquí el Semaphore

 

Un saludo y hasta la próxima,

 

Mario Ropero.

[FW 3.5] Obtener los miembros recursivamente de un grupo en directorio activo

Hola a todos, con el FW 3.5 hay una opción para recoger todos los miembros de un grupo en modo recursivo, así que ya se acabó de ir buscando los miembros del grupo y ver si tenía a su vez miembros y todo el rato lo mismo.

 

Es que estos chicos de .NET son muuuuuy listos. Os pongo un ejemplillo pero es sumamente sencillo.

El espacio de nombres a usar es System.DirectoryServices.AccountManagement

 

string nombreGrupo = "grupo";
string nombreDominio = "dominio";

using (PrincipalContext ctx = new PrincipalContext(ContextType.Domain, nombreDominio))
{
GroupPrincipal grp = GroupPrincipal.FindByIdentity(ctx, IdentityType.Name, nombreGrupo);

if (grp != null)
{

foreach (Principal p in grp.GetMembers(true))
{
Console.WriteLine(p.Name);
}
grp.Dispose();
}
}

 

Y ya está, la gracia está en el GetMembers(true). Una cosa a tener en cuenta es que si el usuario que ejecuta este código no tiene permisos para poder ver un grupo dará un error de “Member not found”, así que es necesario que tenga permisos por lo menos de visualización.

Este post es corto, y creo que va a ser una serie de post para hacer cosas sencillas, porque creo que cuando estoy mucho tiempo sin desarrollar en algo, al final las cosas más sencillas o simples son las que más buscamos, o por lo menos en mi caso que soy un rato zote.

 

Un saludo a todos.

“Ar” Mario Ropero.

System.Transactions y concurrencia

 

Hola a todos, llevo bastante tiempo desconectado y es que el verano me ha sentado mal y estoy muy perruno, pero bueno vamos a ver si podemos hacer algo para remediarlo. Hace tiempo conté un problemita que me surgió con los TransactionScope y su abuso.

 

Esta vez el problema estaba en que un proceso hacía una operación y en un momento llamaba a un hilo en background para procesar otro trabajo, pero todo tenía que estar dentro de la misma transacción o al menos que sólo se hiciese commit si todos los procesos acababan bien.

Bueno pues ahí empezaron mis problemas, porque cuando tú creas un TransactionScope por defecto el crea una transacción (ambient transaction que se llama) y la almacena en el Thread Local Storage (lo que viene siendo el TLS) del hilo en uso y esto hace que no se propague a los nuevos hilos que se generan. Y buscando por la red encontré el whitepaper de un “peaso” de crack que ya me dijeron en su tiempo, el gran Juval Lowy y expone la solución para estos problemas.

 

Os lo pongo aquí, pero realmente creo que es mejor que os bajéis el whitepaper y le echéis un vistazo que no es nada pesado y la verdad explica muy bien cómo funciona todo y el LTM y bueno, clarifica bastante…

 

En el tema de la concurrencia, os pongo un ejemplo de la clase que se ejecutaría sobre uno de los hilos generados

public class Obrero
{
public void Trabaja(DependentTransaction transaccion)
{
Thread thread = new Thread(Metodo);
thread.Start(transaccion);
}

public void Metodo(object transaccion)
{
DependentTransaction tran = transaccion as DependentTransaction;

Transaction antiguaTransaccion = Transaction.Current;

try
{
Transaction.Current = tran;

Debug.WriteLine("Esto tiene que estar dentro de una transacción... o algo similar :)");

tran.Complete();
}
finally
{
//Liberamos la transaccion que hemos pasado y volvemos a poner la transacción a la antigua
tran.Dispose();
Transaction.Current = antiguaTransaccion;
}
}
}

Aquí lo único ha observar, es que  a la clase se le pasa un objeto DepedentTransaction y es el que usa para hacer el Complete() una vez hecho el trabajo que tenga que hacer, en este caso un importantísimo Debug.WriteLine.

 

Desde el “padre” para invocar a esto sería un código similar a esto

using (TransactionScope scope = new TransactionScope())
{
//Vamos a recoger la transacción actual y generar un dependentTransaction a través
//del método DependentClone()
DependentTransaction transaccion = Transaction.Current.DependentClone(DependentCloneOption.BlockCommitUntilComplete);

//Aquí llamo a la clase que generar el hilo y hace otro trabajo transaccional
Obrero obrero = new Obrero();

obrero.Trabaja(transaccion);

Debug.WriteLine("El papi hace cualquiero tipo de trabajo transaccional");

//Este Complete() significa que en este instante se ejecutará el Commit de los hijos y del padre
//debido a la opción de DependentCloneOption que está a BlockCommitUntilComplete, esto quiere decir
//que no se hará ningún commit de los "hijos" hasta que el padre haga el Complete()
scope.Complete();
}

Bueno aquí las cosas importantes son el método DependentClone de la transacción actual y la opción de DependentCloneOption, lo demás no es más que pasarle a la clase que hemos creado antes, la transacción generada y que trabaje sobre ella.

 

Las distintas opciones de DependentCloneOption

Esto es un enumerado que tiene dos opciones, BlockCommitUntilComplete y RollbackIfNotComplete.

La opción BlockCommitUntilComplete, hace que no se ejecuten los commit de las transacciones dependientes hasta que la transacción “padre” haga el Complete(), esto en la practica hace que cuando en una transacción dependiente se haga un Complete(), la transacción se marca como “lista para hacer commit” pero no se ejecuta.

 

La opción RollbackIfNotComplete, hace que si el “padre” ejecuta el Complete() y existe alguna transacción dependiente que todavía no haya hecho un Complete() se generará una TransactionAbortedException, y además el hilo hijo seguirá trabajando para nada porque la transacción ya está abortada.

 

 

La verdad es que esto del System.Transactions tiene bastante miga, seguiré investigando cositas que aunque es una tecnología bastante antigua ya, todavía sigue dando mucha guerra en los proyectos porque no se utiliza correctamente, y por cierto os vuelvo a recomendar a todos leeros el whitepaper de Juval Lowy que mola…

 

Un saludo a todos.

Mario Ropero.