2010-02-08 9 views
6

Esta pregunta se relaciona con un escenario muy específico y común en el que se usa un diccionario para el almacenamiento en caché bajo demanda de artículos en un entorno de subprocesos múltiples. Para evitar el bloqueo de subprocesos es preferible probar un elemento de caché existente fuera de un bloqueo de sincronización, pero si posteriormente tenemos que agregar un elemento, eso cuenta como una escritura en el diccionario y, por lo tanto, la mayoría de los consejos que he estado leyendo en stackoverflow es necesita bloquear tanto la lectura como la escritura porque el estado interno del diccionario podría estar siendo alterado por las llamadas a add().¿Es seguro un hilo de diccionario <K,V> para lecturas simulaneas y adiciones?

Sin embargo, mirando a través de AjaxControlToolkit de Microsoft (clase ScriptObjectBuilder), el código de hecho realiza TryGet() fuera de los bloqueos y solo se bloquea para agregar() nuevos elementos al diccionario. Puedo ver cómo esto podría ser posible si el cubo en el que se coloca un elemento nunca cambia una vez agregado, pero mi sospecha es que esto es incorrecto y podría ser una fuente de errores.

Gracias.

ACTUALIZACIÓN Según la documentación de .Net, creo que el patrón descrito es realmente incorrecto. Sin embargo, me preguntaba si la implementación particular del Diccionario lo permite y que el AjaxControlToolkit confiaba en esto (lo cual sería dudoso). Al examinar el código en Reflector estoy bastante seguro de que esto está realmente mal, el método Dictionary.Resize() reasigna el número de cubos y mueve los elementos del contenedor, por lo que cualquier hebra en el medio de un TryGet() podría estar funcionando en datos inestables.

ACTUALIZACIÓN Un defecto que ya se registra en contra de la AjaxControlToolkit en CodePlex. Ver:

+0

lo has probado? las secuencias de comandos del lado del cliente suelen ser de un solo hilo. se aplican advertencias estándar. –

+0

¿Ha intentado escribir un arnés de prueba para esto usted mismo? Me interesaría ver si esto causa algún problema también. –

+0

Este es el código ajax del lado del servidor.Hay sincronización de subprocesos porque usa diccionarios estáticos en lugares para almacenar datos en caché. – redcalx

Respuesta

-1

Para responder a mi propia pregunta después de algunas inversiones: Al examinar el código del Diccionario, veo que el método Dictionary.Resize() reasigna el número de depósitos internos que se utilizan para almacenar datos y redistribuye el contenido del depósito para que los artículos están en el cubo correcto basado en su código hash. Como tal, cualquier hilo en el medio de un TryGet() se arriesga a trabajar en datos inestables.

Como un lado, un posible enfoque de bajo bloqueo para una clase de diccionario podría ser colocar un bloqueo más allá del método Resize().

+0

La respuesta de Rex M a continuación es más correcta, y he encontrado esto en el código de producción. Sincronice todo, a menos que * cada * hilo sea de solo lectura. ReaderWriterLock [Slim] es apropiado. – FMM

5

Tess Ferrandez tiene una excellent blog post sobre enhebrar problemas con los diccionarios genéricos:

el método FindEntry camina a través del diccionario, tratando de encontrar la clave . Si hay varios subprocesos haciendo esto al mismo tiempo, especialmente si el diccionario se modifica mientras tanto, puede terminar en un bucle infinito en FindEntry causando el alto comportamiento de CPU y el proceso puede bloquearse.

1

Yo diría que esto es definitivamente un error en el AjaxControlToolkit, y le recomendaría que presente un error en CodePlex. Debería estar usando un ReaderWriteLock (Slim).

+0

Gracias. Aparentemente ya estaba registrado en 2007, pero agregué algo de entrada. Ver enlaces en la publicación (arriba) – redcalx

Cuestiones relacionadas