Cuando se necesita asegurar el acceso atómico a un bloque de código determinado tenemos que utilizar alguna forma de bloqueo y sincronizacion. Delphi dispone de varias herramientas para esto (Semáforos, monitores, secciones criticas)
Vamos a ver una de ellas, probablemente la mas sencilla y en mi caso la única que he usado intensivamente.
Una aplicación VCL tradicional no usa mas que un thread o hilo, el hilo principal, por lo tanto no tenemos acceso simultaneo a un recurso. Esto hace que el tema de sincronizacion no nos toque directamente, cuando uno desarrolla una aplicación/servidor de aplicación o servicio multihilo la cosa cambia y hay que tener especial atención al acceso simultaneo a los recursos.
La sección critica
Como dijimos en delphi tenemos una herramienta muy sencilla que es la seccion critica, esta no es mas que una clase de la cual necesitamos solo 2 metodos, uno para entrar a la seccion critica o otro para abandonarla
CS.Enter;
try
//mi código protegido de acceso simultaneo
finally
CS.Leave;
end;
Observe que el código protegido esta dentro de un bloque try-finally, esto no es solo prolijidad o una buena practica, en este caso particular es mandatario. Si una excepción ocurre en “mi código protegido” y no se ejecuta el método Leave nunca se abandona la sección critica, por tanto se bloquean todos los otros threads que intenten ejecutar el código protegido.
Ejemplo para el uso de TcriticalSection en DataSnap
Dependiendo del modelo de lifeCycle seleccionado en cada uno de los ServerClass es muy probable que tengamos varios Threads funcionando en paralelo. ¿Y si quiero que mis ServerModules escriban operaciones, logs de seguimiento o lo que sea en un visor en la pantalla principal?
Acá aparece el problema, supogamos ponemos un memo para loguear actividades de los ServerModules, varios intentaran usar el memo al mismo tiempo produciendo los problemas de concurrencia mencionados.
Ponemos el ejemplo de escribir sobre un memo en la pantalla principal porque es el ejemplo mas sencillo, pero aplica a cualquier uso de un recurso compartido, en este caso el memo.
TCriticalSection
Antes de usar una sección critica hay que crearla, una unidad global puede ser una solución. Probablemente no es la mas elegante ni ortodoxa pero es la que aprendí y no he probado otra por tanto no me voy a arriesgar a proponer nada nuevo para mi.
unit uGlobal;
interface
uses SyncObjs;
var
CSLog:TCriticalSection;
implementation
initialization
CSLog := TCriticalSection.Create;
finalization
CSLog.Free;
end.
Creada la sección critica esta lista para ser usada justo antes de acceder al recurso compartido...
procedure TAbstractServerModule.LogVisor(s: string);
begin
CSLog.Enter;
try
FrmMain.LogVisor(s);
finally
CSLog.Leave;
end;
end;
Ya que estamos, aprovecho mi ServerModule abstracto (ver http://pablosoligo.blogspot.com/2011/06/datasnap-dbexpress-y-threads.html)
para crear la función.Justo antes de usar el recurso compartido entro en la sección critica, justo luego de salir salgo de la misma.
Ahora todos los server modules puede escribir sobre el log, no importa que estén en distintos threads y que lo quieran hacer simultáneamente.
Recordar
- Try-Finally. No podemos dejar una sección critica sin salida, entonces si entro y siempre salgo
- Hacer la sección critica lo mas corta posible para favorecer paralelismo y multitarea
Si editas el memo, como es parte de la VCL y del hilo principal de la aplicacion no deberia usarse algo asi como Synchronize en lugar de una seccion critica ??
ResponderEliminarsaludos :)
Con el Synchronize y la seccion critica logras lo mismo, a veces el Synchronize se queda corto y la seccion critica te puede dar mas margen de maniobra, en ves de bloquear todo el método solo bloqueas los recursos compartidos (Si es que en el método haces muchas cosas)
ResponderEliminarhola pablo buenas tardes, queria pedirte si es posible el codigo de los ejemplos, soy novato y me cuesta seguirte y me queda todo a medias. te agradesco muchisimo si es posible. el codigo de los estos ejemplos de datasnap muchas gracias.
ResponderEliminar