2012-01-02 14 views
11

Tiene dos hilos, ay b. El subproceso a está en un bucle para siempre, escuchando en un zócalo de bloqueo 1. El subproceso b también está en un bucle para siempre, escuchando en el zócalo de bloqueo 2. Tanto el zócalo 1 como zócalo 2 pueden devolver datos en tiempos arbitrarios, por lo que el hilo a puede estar durmiendo para siempre a la espera de datos, mientras que el hilo b recibe constantemente datos del zócalo y continúa con su procesamiento. Ese es el fondo.Haskell Thread Communication Pattern Escenario

Supongamos ahora que necesitan compartir un diccionario. Cuando Thread a obtiene algunos datos (si acaso), agrega un par de valores clave en el diccionario después de algún procesamiento, y luego continúa esperando por más datos. Cuando el Tema b recibe datos de su socket, primero consulta el diccionario para ver si hay información relacionada con los datos que ha recibido antes de continuar con su procesamiento. No hay eliminaciones en el diccionario, solo inserciones y consultas (me interesaría si esto marca una diferencia en la solución final).

En un lenguaje imperativo estándar como python o c, esto es bastante fácil de hacer al hacer disponible el diccionario en ambos ámbitos y consultarlo solo después de que un hilo haya adquirido un bloqueo, por lo que el hilo B siempre es el que más ve (bueno) diccionario actualizado.

En Haskell, parece que estoy luchando para encontrar una buena implementación de este patrón. MVars, solo puede tener un elemento a la vez, por lo que no puede ser que Thread a ponga en el diccionario, ya que podría ocurrir una nueva actualización y no sería capaz de empujar ese nuevo diccionario hasta que Thread b lo haya obtenido de MVar. Por otro lado, si el subproceso b usa un MVar para enviar una señal de listo "¡ok!" para enhebrar a, puede darse el caso de que Thread a duerma en su socket de lectura, por lo que no podría enviar datos hasta que se desbloquee su socket de lectura. También hay canales, pero parece desordenado ya que tendría que seguir enviando nuevos diccionarios y el hilo B descartaría todos menos el último.

La solución alternativa que funcionaría es simplemente enviar las actualizaciones por un canal, y hacer que el hilo B construya el diccionario por sí mismo. Sin embargo, me pregunto si hay mejores soluciones alternativas.

Gracias por tomarse el tiempo para leer esta pregunta tan larga.

+4

No veo el problema con 'MVar's. Si A se despierta y obtiene datos nuevos, intenta 'sacarMVar' el diccionario del' MVar'.Cuando tenga éxito, actualice el diccionario, el diccionario 'putMVar', vuelva a dormir. Cuando B obtiene datos, intente 'takeMVar', busque de vuelta. ¿Dónde se rompe eso? –

+1

¡Gracias! Dispara Lo siento eso es exactamente lo que estaba buscando, no importa. Soy un begineer todavía. Pensé que no podría sacar si se ponía, y solo otro hilo podría hacerlo. Estúpida suposición en la parte posterior de mi cabeza! Simplemente no estoy seguro de cómo cerrar esta pregunta ahora? –

+0

Puedo hacer una respuesta que pueda aceptar para marcar el asunto como resuelto, o puede eliminar la pregunta si lo prefiere (no sé cómo, debería haber un enlace de eliminación en algún lugar, creo). –

Respuesta

10

Puede utilizar un MVar de la siguiente manera:

  • Al hilo A obtiene nuevos datos, se trata de que el diccionario con takeMVar. Cuando eso tiene éxito, actualiza el diccionario y lo vuelve a poner en MVar
  • Cuando el hilo B obtiene datos, intenta obtener el diccionario con takeMVar - en el escenario anterior donde A raramente obtiene datos que deberían tener un éxito bastante rápido en promedio. Luego hace la búsqueda y devuelve el diccionario.

Como hammar señaló, probablemente es mejor no usar directamente takeMVar y putMVar sino envolverlos en modifyMVar_ resp. modifyMVar para no dejar el MVar vacío si un hilo obtiene una excepción al usar el diccionario.

En un hilo, algo así como

modifyMVar_ mvar (\dict -> putMVar mvar (insert newStuff dict)) 

en el subproceso B todo lo que necesita es un simple readMVar (gracias a @hammar de nuevo por señalarlo).

+0

Para el hilo B, creo que un 'readMVar' sería suficiente (y posiblemente sea más eficiente), ya que el diccionario no se está actualizando. – hammar

+0

Probablemente. Es muy poco probable que sea golpeado por una excepción entre la toma y la puesta, pero no imposible. Entonces el 'MVar' podría terminar vacío. Por otro lado, es muy posible que una excepción tenga que matar a todo el proceso de todos modos. –

+0

La implementación de 'readMVar' usa' mask_', así que no creo que pueda ocurrir una excepción entre la toma y la puesta. – hammar