threads - C#multi-threading: ¿Es necesario adquirir bloqueo de lectura?
synlock c# (12)
¿Es necesario adquirir un bloqueo en una variable antes de leerlo desde múltiples hilos?
¿Necesario? No.
... pero si es posible que otro hilo intente escribir durante la lectura (como una colección, etc.), entonces podría ser una buena idea.
Además de las respuestas a continuación, también puedes hacer un bloqueo de lectura usando ReadWriterLockSlim .
Eso le permitiría hacer solo un bloqueo de lectura al leer y un bloqueo de escritura al modificar su variable. Múltiples hilos pueden tener un bloqueo de lectura al mismo tiempo, pero tan pronto como un hilo solicita un bloqueo de escritura, todas las solicitudes nuevas se bloquean hasta que se completa.
Este tipo de bloqueo sería útil si haces muchas lecturas y no muchas escrituras.
Como con la mayoría de los problemas de subprocesamiento múltiple, investigue lo suficiente como para entender si realmente se ajusta a su problema, ReadWriterLock no sería adecuado para cada situación de bloqueo.
Depende de si es o no una variable local o compartida, y si algo más puede escribirle mientras tanto, y qué va a hacer después de leerlo.
Si toma una decisión basada en la variable, considere que la próxima línea de código puede estar basada en datos que ahora están caducados.
Depende del tipo de variable y su plataforma. Por ejemplo, no se garantiza que la lectura de Int64s sea atómica en máquinas de 32 bits. Por lo tanto, Interlocked.Read
.
Es 100% necesario a menos que esté 100% seguro de que el valor de la variable no cambiará mientras se estén ejecutando los subprocesos del lector.
La lectura no requiere un bloqueo; siempre y cuando no te importe la ''corrección'' de la lectura. Solo es peligroso si intentas escribir sin un candado.
La respuesta corta es: depende.
La respuesta larga es:
Si no es un valor compartido, es decir, solo un hilo puede verlo (o usarlo), no necesita ninguna sincronización.
Si es un valor inmutable, es decir, lo configura solo una vez y luego solo lo lee, es seguro hacerlo sin sincronización (siempre y cuando no comience a leer antes de que se complete la primera escritura).
Si se trata de un tipo "primitivo" de como máximo 32 bits (por ejemplo,
byte
,short
,int
), puede obtener datos obsoletos (antiguos) al leer. Si eso no te molesta, estás listo. Si los datos obsoletos no son deseables, hacer que la variable seavolatile
puede solucionar este problema sin sincronización adicional para las lecturas. Pero si tienes escritores de carreras, deberás seguir los mismos consejos que para loslong
figuran a continuación.Si es un tipo "primitivo" de más de 32 bits (por ejemplo,
long
,decimal
,double
) necesita sincronización; de lo contrario, podría leer "la mitad" de un valor, "la mitad" de otro, y obtener resultados disparatados. Para esto, el enfoque recomendado es usar los métodos en la claseInterlocked
, tanto para lecturas como para escrituras.Si es un tipo de referencia, necesitará sincronización para evitar ver un estado inválido (el ejemplo de la imagen de Jeff Lamb es bueno). La instrucción de
lock
puede ser suficiente para eso. De nuevo, debe bloquear tanto las lecturas como las escrituras.
Hay algunos otros puntos a considerar (cuánto tiempo bloquear, por ejemplo), pero creo que estos son suficientes para responder a su pregunta.
La respuesta es que depende. Si el valor de la variable no cambia cuando los hilos están accediendo a la variable. de lo contrario, es necesario.
Además, puede usar la serie Interlocked.XXX para mantener la atomicidad al leer / escribir la variable.
Si es una constante, no.
Si es un valor actualizable, sí, si necesita consistencia.
Para valores actualizables donde debe administrarse el valor exacto, entonces sí, debe usar un candado u otro método de sincronización para lecturas y escrituras; y quizás bloquee durante todo el alcance donde se usa el valor.
Si la carga del valor se realiza en 1 instrucción de ensamblaje, no es necesario obtener un bloqueo. No importa si el valor cambió hace 10 minutos o hace 1 microsegundo. Solo quieres el valor ahora.
Sin embargo, si está cargando una enorme matriz o imagen o algo así, probablemente sería una buena idea bloquearlo. En teoría, puede obtener una apropiación mientras carga los datos y tener la mitad del primer elemento y la mitad del segundo.
Sin embargo, si es una variable simple, como bool o int, no es necesario.
Si la variable nunca es escrita por alguien (al menos en el momento en que es accesible), no es necesario que la bloquee, porque no hay posibilidades de actualizaciones perdidas. Lo mismo ocurre si no te importan las actualizaciones perdidas (lo que significa que no es un problema si obtienes un valor anterior). De lo contrario, deberías usar algún tipo de sincronización
Siempre y cuando no cambie durante la ejecución de otros hilos, no es necesario que lo bloquee. Si cambias, deberías usarlo.