what threads threaded thread single programming multi language cooperative multithreading delphi synchronization

multithreading - threads - thread model



Sincronización para lectores múltiples, escritor único? (7)

Cada vez que el escritor desea acceder, usted pone en cola a los lectores entrantes (pídales que esperen sobre la Condición), espere a que los lectores activos finalicen, escriban y, cuando finalice, permita que los lectores en cola entren en contacto.

Otra pregunta de sincronización ... Espero que no se enfaden;)

Supongamos el siguiente escenario: una estructura de datos central (muy grande, por lo que realmente no quiero que sea inmutable y la copie cada vez que ocurre un cambio. Incluso no quiero mantener múltiples copias en la memoria), varios hilos de lectura que acceda a esa estructura de datos de solo lectura y una secuencia de escritura que mantiene la estructura de datos actualizada en segundo plano.

Actualmente sincronizo todos los accesos a la estructura de datos, que funciona muy bien (sin efectos de sincronización, sin interbloqueos). Lo que no me gusta de este enfoque es que la mayoría de las veces tengo muchos hilos de lectura activos y el hilo del escritor solo está activo de vez en cuando. Ahora es completamente innecesario que los hilos del lector esperen a que otros subprocesos del lector finalicen. Podrían acceder fácilmente a la estructura de datos en paralelo siempre que el hilo del escritor no esté escribiendo en ese momento.

¿Hay alguna manera agradable y elegante de resolver este tipo de situaciones?

EDITAR: ¡ Muchas gracias por las respuestas y los enlaces! Permítanme agregar solo otra pregunta breve y relacionada: si el código ejecutado dentro de las secciones críticas del lector toma solo un tiempo muy corto (como solo una búsqueda en una tabla hash), ¿vale la pena considerar implementar una de las técnicas que describe o la serialización? efecto de las cerraduras no tan mal en este caso? La escalabilidad y el rendimiento son muy importantes. ¿Qué piensas?

EDIT 2: Acabo de examinar una implementación de un solo escritor / múltiples lectores - lock y esta implementación utiliza un monitor para sincronizar algunos códigos en el método WaitToRead. ¿No causa esto el mismo efecto de serialización que quería evitar en primer lugar? (Aún suponiendo que el código que se sincronizará es corto y rápido)


El bloqueo lector-escritor es lo que necesita. El tutorial tiene una descripción, pero estoy seguro de que alguien estaba agregando esto de manera estándar a Delphi. Puede valer la pena comprobar que D2009 ya no lo tiene.


Hay una clase para ese propósito en RTL (sysutils): TMultiReadExclusiveWriteSynchroniser

Es muy fácil de usar. No necesita categorizar estrictamente sus hilos como lector o escritor. Simplemente llame a "BeginRead" o "BeginWrite" en una secuencia para iniciar una operación segura de subprocesos. Llame a "EndRead" o "EndWrite" para finalizar la operación.



Nadie puede realmente responder a su pregunta sobre si la serialización afectará mucho el rendimiento de su aplicación: tiene que crear un perfil para usted y los resultados dependerán en gran medida de la cantidad de hilos, núcleos y la carga de trabajo específica.

Sin embargo, tenga en cuenta que el uso de una sincronización más inteligente que las secciones críticas, como el lector-escritor-bloqueo, puede presentar problemas de inanición que pueden ser difíciles de depurar y corregir. Realmente necesita mirar con cuidado si el aumento en el rendimiento supera los posibles problemas. Tenga en cuenta también que no puede haber un aumento en el rendimiento, especialmente si el código bloqueado es muy corto y rápido. Hay un buen artículo de Jeffrey Richter que en realidad contiene esta cita:

Rendimiento Incluso cuando no hay contención para un ReaderWriterLock, su rendimiento es muy lento. Por ejemplo, una llamada a su método AcquireReaderLock tarda aproximadamente cinco veces más en ejecutarse que una llamada al método Enter de Monitor.

Esto es para .NET, por supuesto, pero los principios subyacentes sí se aplican también.


Usar un bloqueo Reader-Writer resolverá el problema. Varios lectores pueden acceder a una base de datos y un escritor obtiene un bloqueo una vez que todos los lectores han terminado de leer.

Sin embargo, esto podría hacer que el escritor nunca tenga acceso a la fuente, ya que siempre hay nuevos lectores que desean tener acceso. Esto puede resolverse bloqueando a los lectores nuevos cuando un escritor quiere acceder: el escritor tiene una prioridad mayor. El escritor obtiene acceso una vez que todos los lectores en la fuente han terminado de leer.