Programador (patrón de diseño)
La versión actual de la página aún no ha sido revisada por colaboradores experimentados y puede diferir significativamente de la
versión revisada el 28 de mayo de 2019; las comprobaciones requieren
4 ediciones .
Un programador es un patrón de diseño paralelo que proporciona un mecanismo para implementar una política de programación, pero no depende de ninguna política en particular. Controla el orden en que los subprocesos deben ejecutar el código secuencial mediante un objeto que especifica explícitamente la secuencia de subprocesos en espera.
Motivos
- Múltiples subprocesos pueden acceder a un recurso al mismo tiempo, y solo un subproceso a la vez puede acceder a un recurso.
- De acuerdo con los requisitos del programa , los subprocesos deben acceder al recurso en un orden determinado.
Ejemplo de implementación
Ejemplo de C#
utilizando el sistema ;
espacio de nombres Digital_Patterns.Concurrency.Sheduler
{
class Printer
{
private static Int32 mID = 0 ;
Planificador privado _planificador = nuevo Planificador ();
Public void Print ( Entrada en el diarioEntrada en el diario )
{
Int32 id = ++ mID ;
prueba
{
Consola . WriteLine ( Cadena . Formato ( @"{0}: ingrese el programador" , id ));
// la llamada no se ejecutará hasta que el objeto Scheduler
// decida que es hora de imprimir este
objeto JournalEntry _scheduler . Enter ( entrada del diario );
consola _ WriteLine ( Cadena . Formato ( @"{0}: comenzar a imprimir" , id ));
intente
{
//TODO Algo
journalEntry . Hacer ( identificación );
}
finalmente
{
// llamar al método Done le dice al Programador que // el objeto JournalEntry ha sido
impreso, y otro
// objeto JournalEntry
_scheduler puede estar al lado de imprimir . Listo ();
consola _ WriteLine ( String . Format ( @"{0}: done scheduler" , id ));
}
}
captura ( Excepción ) {}
}
}
}
utilizando el sistema ;
usando System.Collections.Generic ;
utilizando System.Threading ;
espacio de nombres Digital_Patterns.Concurrency.Sheduler
{
/// <summary>
/// Las instancias de clase en este rol controlan el procesamiento de los objetos Request <see cref="JournalEntry"/>
/// realizado por el objeto Processor <see cref="Printer "/> . Para ser independiente de
/// los tipos de solicitud, la clase <see cref="Scheduler"/> no necesita saber nada sobre la clase de solicitud que administra.
/// En su lugar, accede a los objetos Request a través de la interfaz que implementan <see cref="ISchedulerOrdering"/>
/// </summary>
class Scheduler
{
/// <summary>
/// Objeto de sincronización de subprocesos
/// < / resumen>
privado AutoResetEvent _event = nuevo AutoResetEvent ( falso );
/// <summary>
/// Se establece en nulo si el recurso administrado por el programador está inactivo.
/// </summary>
subproceso privado _subproceso en ejecución ;
/// <summary>
/// Threads y sus solicitudes en espera
/// </summary>
private Dictionary < Thread , ISchedulerOrdering > _waiting = new Dictionary < Thread , ISchedulerOrdering >();
/// <summary>
/// Se llama al método <see cref="Enter"/> antes de que el subproceso comience a usar el recurso administrado.
/// El método no se ejecuta hasta que se libera el recurso administrado y el objeto <see cref="Sheduler"/>
/// decide que la cola de ejecución de esta solicitud ha llegado
/// </summary>
/// <param name ="s"></param>
public void Enter ( ISchedulerOrdering s )
{
var thisThread = Thread . HiloActual ;
lock ( this )
{
// Determina si el programador está ocupado
if ( _runningThread == null )
{
// Inmediatamente comienza a ejecutar la solicitud entrante
_runningThread = thisThread ;
volver ;
}
_esperando . Agregar ( este subproceso , s );
}
lock ( thisThread )
{
// Bloquea el hilo hasta que el planificador decida convertirlo en el hilo actual
while ( thisThread != _runningThread )
{
_event . esperar uno ();
_evento . conjunto (); // permite que otros subprocesos verifiquen su estado
Thread . dormir ( 1 );
}
_evento . restablecer ();
}
bloquear ( esto )
{
_esperando . Quitar ( esteHilo );
}
}
/// <summary>
/// Llamar al método <see cref="Done"/> indica que el hilo actual ha terminado
/// y el recurso administrado ha sido liberado
/// </summary>
public void Done ()
{
lock ( this )
{
if ( _runningThread != Thread . CurrentThread )
lanza una nueva excepción ThreadStateException ( @ "Subproceso incorrecto" );
Int32 waitCount = _esperando . contar ;
if ( waitCount <= 0 )
{
_runningThread = null ;
}
else if ( waitCount == 1 )
{
_runningThread = _esperando . primero (). clave ;
_esperando . Eliminar ( _runningThread );
_evento . conjunto ();
}
else
{
var siguiente = _esperando . primero ();
foreach ( var esperar en _esperando )
{
if ( esperar . Valor . ScheduleBefore ( siguiente . Valor ))
{
siguiente = esperar ;
}
}
_subproceso en ejecución = siguiente . clave ;
_evento . conjunto ();
}
}
}
}
/// <summary>
/// Clase auxiliar
/// </summary>
clase parcial estática ConvertTo { /// <summary> /// Obtiene el primer elemento de la colección /// </summary> /// < param name= "colección"></param> /// <devoluciones></devoluciones> public static KeyValuePair < Thread , ISchedulerOrdering > First ( este Diccionario < Thread , ISchedulerOrdering > colección ) { foreach ( var elemento en colección ) { artículo de vuelta ; } lanza una nueva ArgumentException (); } }
}
utilizando el sistema ;
espacio de nombres Digital_Patterns.Concurrency.Sheduler
{
/// <summary>
/// Si varias operaciones están esperando para acceder a un recurso, la clase <see cref="Scheduler"/>
/// utiliza esta interfaz para determinar el orden en el que se deben realizar las operaciones.
/// </summary>
interfaz ISchedulerOrdering
{
Boolean ScheduleBefore ( ISchedulerOrdering s );
}
}
utilizando el sistema ;
utilizando System.Threading ;
espacio de nombres Digital_Patterns.Concurrency.Sheduler
{
/// <summary>
/// Ejemplo de código de clase <see cref="JournalEntry"/> que será
/// impreso por <see cref="Printer"/>
/// < /summary >
class JournalEntry : ISchedulerOrdering
{
private static DateTime mTime = DateTime . ahora ;
fecha y hora privada _hora ;
/// <summary>
/// Devuelve la hora de creación de este objeto
/// </summary>
public DateTime Time { get { return _time ; } }
privado String_msg ; _
public JournalEntry ( String msg )
{
mTime = mTime . AñadirSegundos ( 1 );
_tiempo = mTiempo ;
_mensaje = mensaje ;
}
public void Do ( Int32 id )
{
Consola . WriteLine ( String . Format ( @"{0}: Empezar a hacer : {1} : {2}" , id , _time , _msg ));
hilo _ Dormir ( 1000 );
consola _ WriteLine ( String . Format ( @"{0}: Finish do : {1} : {2}" , id , _time , _msg ));
}
/// <summary>
/// Devuelve verdadero si esta solicitud
/// debe procesarse antes de esta solicitud.
/// </summary>
/// <param name="s"></param>
/// <returns></returns>
public Boolean ScheduleBefore ( ISchedulerOrdering s )
{
if ( s is JournalEntry )
{
var otherJournalEntry = ( Entrada de diario ) s ;
return ( this . Time < otherJournalEntry . Time );
}
devuelve falso ;
}
}
}
utilizando el sistema ;
utilizando System.Threading ;
espacio de nombres Digital_Patterns.Concurrency.Sheduler
{
public class Example01
{
private Printer _printer ;
public void Ejecutar ()
{
Consola . WriteLine ( @"Presione cualquier tecla para comenzar y presione nuevamente para finalizar" );
consola _ Clave de lectura ();
_impresora = nueva impresora ();
nuevo Hilo ( Hilo1 ). Inicio ();
nuevo Hilo ( Hilo2 ). Inicio ();
Hilo nuevo ( Hilo3 ). Inicio ();
consola _ Clave de lectura ();
}
privado void Thread1 ()
{
var msg1 = new JournalEntry ( @ "Comprar peaje 5.45 USD" );
var msg2 = new JournalEntry ( @"Comprar caramelos 1,05 USD" );
var msg3 = new JournalEntry ( @"Comprar chocolate 3,25 USD" );
_impresora . Imprimir ( mensaje1 );
_impresora . Imprimir ( mensaje2 );
_impresora . Imprimir ( msg3 );
}
subproceso vacío privado2 () { var msg4 = nueva entrada de diario ( @ "Comprar postal 2.05 USD" ); var msg5 = new JournalEntry ( @"Comprar gerland 37,78 USD" ); _impresora . Imprimir ( msg4 ); _impresora . Imprimir ( msg5 ); }
privado void Thread3 ()
{
var msg6 = new JournalEntry ( @ "Comprar bola 30.06 USD" );
var msg7 = new JournalEntry ( @"Buy pipe 1.83 USD" );
_impresora . Imprimir ( msg6 );
_impresora . Imprimir ( msg7 );
}
}
}
utilizando el sistema ;
utilizando Digital_Patterns.Concurrency.Sheduler ;
espacio de nombres Digital_Patterns
{
class Program
{
static void Main ( cadena [] args )
{
new Example01 (). ejecutar ();
consola _ WriteLine ( @"Presione cualquier tecla para finalizar" );
consola _ Clave de lectura ();
}
}
}
Enlaces
- Marca grandioso. Patrones en Java Volumen 1: un catálogo de patrones de diseño reutilizables ilustrados con UML. - Wiley & Sons, 1998. - 480 p. — ISBN 0471258393 . (ver sinopsis (inglés) )