|
Página 3 de 5
A continuación se explica cómo iniciar el entorno CCR. Primero se crea un objeto Dispatcher y otro DispatcherQueue. Posteriormente se ejecutan varios métodos en los que podemos comprobar el funcionamiento del CCR. En este caso, todos los métodos usan el mismo elemento Dispatcher. Dado que el objeto Dispatcher se crea dentro de una cláusula using, se llamará automáticamente al método Dispose al finalizar el bloque de código [Fuente: MSDN Magazine. Concurrent Affairs].
public static void Main() { // Crea un Dispatcher (Thread Pool) using (Dispatcher dispatcher = new Dispatcher(0, "CCR Demo Threads")) { // Crea una cola DispatcherQueue que encola las tareas del Dispatcher DispatcherQueue dq = new DispatcherQueue("CCR Demo DispatcherQueue", dispatcher);
// Ejecutar demos SpawnDemo(dq); PortArbiterDemo(dq); MultipleItemDemo(dq); ... } }
El método SpawnDemo demuestra como generar una tarea usando el pool de hilos del CCR. En este ejemplo, se define un método anónimo que llama al método Msg. C# genera automáticamente un delegado para este método anónimo, y este delegado se le pasa al método estático FromHandler. Después se llama al método estático Activate para encolar el método correspondiente a la tarea en el objeto DispatcherQueue.
private static void SpawnDemo(DispatcherQueue dq) { Arbiter.Activate(dq, Arbiter.FromHandler( delegate { Msg("Handler"); }) ); HitEnter(); // esperar la entrada del usuario para continuar }
private static void Msg(String format, params Object[] args) { Console.Write("ThreadID={0}: ", Thread.CurrentThread.ManagedThreadId); Console.WriteLine(format, args); }
private static void HitEnter() { Thread.Sleep(250); // Dar tiempo para que termine una operación Console.Write("Hit <Enter> to continue demo"); Console.ReadLine(); Console.WriteLine(); }
A continuación vemos como un objeto Port y Arbiter trabajan juntos. Primero construimos un objeto Port<string>, que soporta objetos string, y que internamente contiene una FIFO (First In First Out) con referencias a objetos String. El objeto Port también mantiene una lista de objetos ReceiverTask. Finalmente, llamamos al método Post() que agrega el elemento String.
private static void PortArbiterDemo(DispatcherQueue dq) { Port<String> stringPort = new Port<String>(); stringPort.Post("StringA");
Lo siguiente que podemos hacer es llamar al método Arbiter.Receive, que crea un objeto ReceiverTask(). El primer argumento, la persistencia, si está a false indica que el objeto ReceiverTask sólo se usará para recibir un elemento. Es decir, mientras está tratando el elemento en cuestión, no debería tratar a otro elemento. El segundo argumento llama al objeto ReceiverTask() con el puerto que debería recibir el elemento. Y el tercer argumento, es un delegado que indica a qué método se debería llamar para procesar el elemento que se ha recibido en el puerto.
Arbiter .Activate(dq, Arbiter.Receive(false, stringPort, delegate(String s) { Msg("Handling string={0}", s); }) );
Debemos dejar claro que la llamada al método Arbiter.Receive simplemente construye un objeto ReceiverTask, este objeto no está registrado en el puerto todavía. Además, es necesario decirle al objeto ReceiverTask que objeto DispatcherQueue llamará al siguiente método. En el momento en el que se llama al método Arbiter.Activate se registra el objeto ReceiverTask con el puerto, aunque el puerto comprueba el elemento antes de ser registrado. Si el objeto ReceiverTask() quiere el elemento, el Distpacher ejecutará el método indicado que realiza el proceso sobre elemento.
Desde que se creó el objeto ReceiverTask, la persistencia está a false, esto permite que el objeto ReceiverTask sólo use un elemento el puerto registrado se dé de baja una vez procesado un elemento. En el siguiente fragmento de código, tenemos la persistencia a true, con esto lo que conseguimos es que cuando un elemento usa el puerto, el objeto ReceiverTask no lo la de baja automáticamente, sino que todos los elementos que están en la cola del puerto serán usados e incluso nuevos elementos que posteriormente se añadan.
Arbiter .Activate(dq, Arbiter.Receive(true, stringPort, delegate(String s) { Msg("Handling string={0}", s); }) );
for (int i = 0; i < 10; i++) { stringPort.Post("String #" + i.ToString()); }
|