Estoy realizando dos actualizaciones en un valor que obtengo de TryGet. Me gustaría saber cuál de estos es mejor.
Opción 1: ¿Bloquear solo el valor?
if (HubMemory.AppUsers.TryGetValue(ConID, out OnlineInfo onlineinfo)) { lock (onlineinfo) { onlineinfo.SessionRequestId = 0; onlineinfo.AudioSessionRequestId = 0; onlineinfo.VideoSessionRequestId = 0; } }
Opción 2: ¿Bloquear todo el diccionario?
if (HubMemory.AppUsers.TryGetValue(ConID, out OnlineInfo onlineinfo)) { lock (HubMemory.AppUsers) { onlineinfo.SessionRequestId = 0; onlineinfo.AudioSessionRequestId = 0; onlineinfo.VideoSessionRequestId = 0; } }
Si solo necesita bloquear el valor del diccionario , por ejemplo, para asegurarse de que los 3 valores se establezcan al mismo tiempo. Entonces realmente no importa qué tipo de referencia bloquee, siempre que sea un tipo de referencia , sea la misma instancia , y todo lo demás que necesite leer o modificar esos valores también está bloqueado en la misma instancia .
Puede leer más sobre cómo la implementación de Microsoft CLR trata el bloqueo y cómo y por qué los bloqueos funcionan con tipos de referencia aquí.
¿Por qué los bloqueos requieren instancias en C#?
Si está tratando de tener consistencia interna con el diccionario y el valor, es decir, si está tratando de proteger no solo la consistencia interna del diccionario y la configuración y lectura del objeto en el diccionario. Entonces su bloqueo no es apropiado en absoluto.
Debería colocar un candado alrededor de la declaración completa (incluido TryGetValue
) y cualquier otro lugar donde agregue al diccionario o lea/modifique el valor. Una vez más, el objeto que encierres no es importante, siempre que sea consistente.
Nota 1 : es normal usar una instancia dedicada para bloquear (es decir, algún object
instanciado) ya sea estáticamente o un miembro de la instancia según sus necesidades, ya que hay menos posibilidades de que se dispare en el pie.
Nota 2 : hay muchas más formas de implementar la seguridad de subprocesos aquí, según sus necesidades, si está satisfecho con los valores obsoletos, si necesita cada onza de rendimiento y si tiene un título en codificación de bloqueo mínima y cuánto el esfuerzo y la seguridad innata en los que desea hornear. Y eso depende totalmente de usted y su solución .
La primera opción (bloquear la entrada del diccionario) es más eficiente porque es poco probable que cree una contención significativa para el bloqueo. Para que esto suceda, dos subprocesos deben intentar actualizar la misma entrada al mismo tiempo. La segunda opción (bloquear todo el diccionario) es bastante posible para crear contención bajo un uso intensivo, porque dos subprocesos se sincronizarán incluso si intentan actualizar diferentes entradas al mismo tiempo.
La primera opción también tiene más el espíritu de usar un ConcurrentDictionary<K,V>
en primer lugar. Si va a bloquear todo el diccionario, también puede usar un Dictionary<K,V>
normal en su lugar. Con respecto a este dilema, puede encontrar interesante esta pregunta: ¿Cuándo debo usar ConcurrentDictionary and Dictionary?