Los nodos de proceso de mensajes y los analizadores deben trabajar en un entorno de varias instancias y varias hebras. Pueden haber muchos objetos de nodo o muchos objetos de analizador y cada uno de los cuales puede tener muchos elementos de sintaxis, y pueden haber muchas hebras que ejecuten métodos en estos objetos. El diseño del intermediario de mensajes asegura que un objeto de mensaje y cualquier objeto que posea lo utilice solamente la hebra que recibe y procesa el mensaje a través del flujo de mensajes.
Una instancia de un nodo de proceso de flujo de mensajes la comparten y la utilizan todas las hebras que dan servicio al flujo de mensajes en el que se ha definido el nodo. En el caso de los analizadores, sólo una hebra individual del flujo de mensajes utiliza una instancia de analizador.
Una extensión definida por el usuario debe seguir este modelo y debe evitar el uso de datos o de recursos globales que requieran semáforos para serializar el acceso entre las hebras. Dicha serialización puede dar como resultados cuellos de botella de rendimiento.
Las funciones de implementación de extensiones definidas por el usuario deben ser reentrantes y cualquier función que invoquen también debe serlo. Todas las funciones del programa de utilidad de extensiones definidas por el usuario son totalmente reentrantes.
Aunque una extensión definida por el usuario puede abarcar hebras adicionales, si es necesario, resulta esencial que la misma hebra devuelva el control al intermediario al finalizar la función de implementación. De no hacerlo se compromete la integridad del intermediario y los resultados pueden ser imprevisibles.
El siguiente ejemplo de flujo de mensajes le ayudará a comprender algunas de las consideraciones de trabajo con hebras que debe tener en cuenta cuando diseñe e implemente sus propios nodos definidos por el usuario. Tiene en cuenta el ejemplo de un nodo de entrada definido por el usuario.
Se puede configurar un flujo de mensajes para que se ejecute en un conjunto de hebras. Esto lo determina el número de nodos de entrada del flujo de mensajes y el valor de la propiedad additionalInstances del flujo de mensajes. Estos dos elementos determinan la capacidad máxima que la agrupación de hebras del flujo de mensajes puede utilizar. Por lo tanto, si el flujo de mensajes tiene requisitos de proceso determinados que dictan que la ejecución debe ser de una sola hebra, debe asegurarse de que así sea.
La forma más eficaz de impedir que la cola de entrada se convierta en un cuello de botella es permitir que el intermediario inicie copias adicionales de la propiedad additionalInstances. No obstante, crear hebras diferentes permite un proceso paralelo de los mensajes de la cola de mensajes, por lo tanto, sólo se utiliza esta propiedad cuando el orden en que se procesan los mensajes no es importante.
Las hebras se crean como resultado de la creación y operación de nodos de entrada. Una hebra permanece activa o desocupada en la agrupación de hebras, las hebras desocupadas permanecen en la agrupación hasta que las despacha un nodo de entrada o hasta que concluye el intermediario.
La figura siguiente muestra la asignación de hebras en un flujo de mensajes.
Asignación de hebras en un flujo de mensajes
Inicialmente, se solicita la hebra 1 (A) y ésta espera los mensajes. Cuando llega un mensaje (B), la hebra 1 propaga el mensaje y despacha la hebra 2. La hebra 2 recibe un mensaje inmediatamente (C) y propaga y despacha la hebra 3, la cual espera un mensaje (D). La hebra 1 se completa (E) y regresa a la agrupación de hebras. La hebra 3 recibe a continuación un mensaje (F), despacha la hebra 1 y propaga el mensaje. Ahora la hebra 1 espera a que llegue el mensaje en la cola (G).
Vale la pena tener en cuenta el punto marcado con una H. En este punto del flujo de mensajes, la hebra 1 adquiere un mensaje pero debido a que todas las demás hebras están activas en ese momento, no se puede despachar. El mensaje se propaga.
Después de que se ha propagado este mensaje, la hebra 2 se completa (I), recibe un mensaje nuevo de la cola y propaga este mensaje nuevo. A continuación, la hebra 3 se completa (J) y regresa a la agrupación. A continuación, la hebra 2 se completa (K). Debido a que no se ha despachado, cuando se completa la hebra 1 (L) no puede regresar a la agrupación de hebras incluso cuando no hay mensajes en la cola y, en su lugar, espera a que llegue un mensaje en la cola.