palabra clave de locking en C #

Entiendo la función principal de la palabra clave de locking de MSDN

Declaración de locking (Referencia C #)

La palabra clave de locking marca un bloque de instrucciones como una sección crítica al obtener el locking de exclusión mutua para un objeto determinado, ejecutar una instrucción y luego liberar el locking.

¿Cuándo se debe usar la cerradura?

Por ejemplo, tiene sentido con aplicaciones de subprocesos múltiples porque protege los datos. ¿Pero es necesario cuando la aplicación no genera ningún otro hilo?

¿Hay problemas de rendimiento con el uso de locking?

Acabo de heredar una aplicación que está usando el locking en todas partes, y es de un solo hilo y quiero saber si debo dejarlos, ¿son necesarios?

Tenga en cuenta que esto es más una pregunta de conocimiento general, la velocidad de la aplicación es buena, quiero saber si ese es un buen patrón de diseño a seguir en el futuro o si debe evitarse a menos que sea absolutamente necesario.

¿Cuándo se debe usar la cerradura?

Se debe usar un locking para proteger los recursos compartidos en código multiproceso. No para nada más.

¿Pero es necesario cuando la aplicación no genera ningún otro hilo?

Absolutamente no. Es solo una pérdida de tiempo. Sin embargo, asegúrese de no utilizar implícitamente los hilos del sistema. Por ejemplo, si usa E / S asíncrona, puede recibir devoluciones de llamada de un hilo aleatorio, no de su hilo original.

¿Hay problemas de rendimiento con el uso de locking?

Sí. No son muy grandes en una aplicación de subproceso único, pero ¿por qué hacer llamadas que no necesita?

… si ese es un buen patrón de diseño a seguir en el futuro [?]

Bloquear todo lo que quiera o no es un patrón de diseño terrible. Si su código está desordenado con un locking aleatorio y luego decide usar un hilo de fondo para algún trabajo, es probable que se encuentre con puntos muertos. Compartir un recurso entre varios hilos requiere un diseño cuidadoso, y cuanto más puedas aislar la parte difícil, mejor.

Todas las respuestas aquí parecen correctas: la utilidad de las cerraduras es bloquear los hilos de un código bloqueado al mismo tiempo. Sin embargo, hay muchas sutilezas en este campo, una de las cuales es que los bloques bloqueados de código se marcan automáticamente como regiones críticas por Common Language Runtime.

El efecto del código que se marca como crítico es que, si la región completa no se puede ejecutar por completo, el tiempo de ejecución puede considerar que todo el dominio de la aplicación está potencialmente en peligro y, por lo tanto, descargarlo de la memoria. Para citar a MSDN :

Por ejemplo, considere una tarea que intenta asignar memoria mientras mantiene un locking. Si la asignación de memoria falla, cancelar la tarea actual no es suficiente para garantizar la estabilidad del AppDomain, ya que puede haber otras tareas en el dominio esperando el mismo locking. Si la tarea actual finaliza, otras tareas podrían estar en punto muerto.

Por lo tanto, aunque su aplicación sea de un solo hilo, esto puede ser un peligro para usted. Considere que un método en un bloque bloqueado arroja una excepción que eventualmente no se maneja dentro del bloque. Incluso si la excepción se reparte mientras sube la stack de llamadas, su región crítica de código no finalizó normalmente. ¿Y quién sabe cómo reactjsrá el CLR?

Para obtener más información, lea este artículo sobre los peligros de Thread.Abort () .

Tenga en cuenta que puede haber razones por las cuales su aplicación no es tan simple como usted piensa. Async I / O en .NET bien puede devolver la llamada en un hilo de grupo, por ejemplo, como lo hacen algunas de las diversas clases de temporizador (no el temporizador de Windows Forms).

En general, si su aplicación es de un solo hilo, no obtendrá mucho uso de la instrucción de locking. Al no conocer su solicitud exactamente, no sé si son útiles o no, pero sospecho que no. Además, si su aplicación está utilizando el locking en todas partes, no sé si sentiría toda la confianza de que funciona en un entorno de subprocesos múltiples de todos modos: ¿el desarrollador original realmente sabía cómo desarrollar código de subprocesos múltiples? simplemente agregan declaraciones de locking en todas partes con la vaga esperanza de que eso sea suficiente.

se debe usar el locking alrededor del código que modifica el estado compartido, estado que otros subprocesos modifican al mismo tiempo, y esas otras bandas deben tener el mismo locking.

Un locking es en realidad un serializador de acceso a memoria, los hilos (que llevan el locking) esperarán en el locking para entrar hasta que el hilo actual salga del locking, por lo que el acceso a la memoria se serializará.

Para responder a su pregunta, el locking no es necesario en una sola aplicación con subprocesos, y sí tiene efectos secundarios en el rendimiento. porque los lockings en C # se basan en objetos de sincronización del núcleo y cada locking que realiza crea una transición al modo kernel desde el modo de usuario.

Si está interesado en el rendimiento de subprocesos múltiples, un buen punto de partida es MSDN Threading Guidelines.

Puede tener problemas de rendimiento con las variables de locking, pero normalmente, construiría su código para minimizar la cantidad de tiempo que pasan dentro de un bloque de código “bloqueado”.

En cuanto a quitar las cerraduras. Dependerá de qué está haciendo exactamente el código. A pesar de que tiene un único hilo, si su objeto se implementa como Singleton, es posible que tenga varios clientes utilizando una instancia del mismo (en la memoria, en un servidor) al mismo tiempo.

Sí, habrá alguna penalización en el rendimiento cuando se usa el candado, pero generalmente es lo suficientemente negligente como para no importar.

El uso de lockings (o cualquier otra statement o construcción de exclusión mutua) generalmente solo se necesita en escenarios de subprocesos múltiples en los que múltiples hilos (ya sea de su propia creación o de quien llama) tienen la oportunidad de interactuar con el objeto y cambiar el estado subyacente o datos mantenidos. Por ejemplo, si tiene una colección a la que se puede acceder mediante varios subprocesos, no quiere que un subproceso cambie el contenido de esa colección eliminando un elemento mientras otro subproceso intenta leerlo.

Lock (token) solo se usa para marcar uno o más bloques de código que no deberían ejecutarse simultáneamente en múltiples hilos. Si su aplicación es de subproceso único, protege contra una condición que no puede existir.

Y el locking invoca un golpe de rendimiento, agregando instrucciones para verificar el acceso simultáneo antes de que se ejecute el código. Solo debe usarse cuando sea necesario.

Vea la pregunta sobre ‘Mutex’ en C #. Y luego mira estas dos preguntas con respecto al uso de la statement ‘lock (Object)’ específicamente.

No tiene sentido tener lockings en la aplicación si solo hay un hilo y sí, es un golpe de rendimiento aunque requiere un buen número de llamadas para que ese golpe se acumule en algo significativo.