Pregunta

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

Supongamos el siguiente escenario: una estructura de datos central (muy grande, por lo que realmente no quiero hacerlo inmutable y copiarlo cuando ocurra un cambio. Incluso no quiero guardar varias copias en la memoria), varios subprocesos de lectores que acceden a esa estructura de datos de solo lectura y un subproceso de escritura que mantiene la estructura de datos actualizada en segundo plano.

Actualmente sincronizo todos los accesos a la estructura de datos, que funciona 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 subprocesos de lectores activos y el subproceso de escritura solo está activo de vez en cuando. Ahora es completamente innecesario que los hilos del lector esperen a que terminen otros hilos del lector. Podrían acceder fácilmente a la estructura de datos en paralelo siempre que el hilo del escritor no esté escribiendo actualmente.

¿Existe una forma agradable y elegante de resolver este tipo de escenario?

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

EDIT 2: Acabo de ver una implementación de un solo escritor / varios lectores: bloqueo y esta implementación usa 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? (Suponiendo que el código a sincronizar sea corto y rápido)

¿Fue útil?

Solución

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

Es muy fácil de usar. No necesitas categorizar estrictamente tus hilos como lector o escritor. Simplemente llame a " BeginRead " o " BeginWrite " en un hilo para iniciar una operación segura de hilo. Llame a " EndRead " o " EndWrite " Para terminar la operación.

Otros consejos

Lo que está buscando (y lo que describió vartec) se llama Reader (s) -Writer -Lock .

Puede encontrar algunas notas detalladas sobre cómo resolver este problema en msdn magazine y un extracto de aplicaciones de programación para MS Windows .

El uso de un bloqueo de 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 acceder. Esto se puede resolver bloqueando a los nuevos lectores cuando un escritor quiere acceder: el escritor tiene una mayor prioridad. El escritor obtiene acceso una vez que todos los lectores de la fuente han terminado de leer.

Cuando el escritor desea acceder, usted pone en cola a los lectores entrantes (haga que esperen la Condición), espere a que los lectores activos finalicen, escriba y cuando termine, permita que los lectores en cola accedan.

En realidad, nadie puede responder a su pregunta si la serialización afectará mucho el rendimiento de su aplicación. Debe hacerlo usted mismo, y los resultados dependerán en gran medida de la cantidad de subprocesos, 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 introducir problemas de hambre que pueden ser difíciles de corregir y corregir. Realmente necesita mirar detenidamente si el aumento del rendimiento supera los problemas potenciales. Tenga en cuenta también que es posible que no haya 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 del monitor.

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

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

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top