C# no permite el bloqueo en un valor nulo. Supongo que podría verificar si el valor es nulo o no antes de bloquearlo, pero dado que no lo he bloqueado, podría aparecer otro hilo y el valor será nulo. ¿Cómo puedo evitar esta condición de carrera?¿Por qué C# no permite que se bloquee un valor nulo?
Respuesta
bloqueo en un valor que no es nulo, por ejemplo,
Object _lockOnMe = new Object();
Object _iMightBeNull;
public void DoSomeKungFu() {
if (_iMightBeNull == null) {
lock (_lockOnMe) {
if (_iMightBeNull == null) {
_iMightBeNull = ... whatever ...;
}
}
}
}
También tenga cuidado de evitar esta condición de carrera interesante con bloqueo doble comprobación: Memory Model Guarantees in Double-checked Locking
Sería bueno agregar solo al objeto de bloqueo para invocar la inmutabilidad deseada – cordialgerm
¿Por qué el bloqueo _lockOnMe puede impedir que otros accedan a _iMightBeNull? –
-1: Tu código aún es susceptible a la condición de carrera con la que te vinculaste; '_iMightBeNull' debe declararse como volátil. O, preferiblemente, uno solo debe usar 'Lazy
Hay dos cuestiones aquí:
En primer lugar, no se bloquean en un objeto null
. No tiene sentido, ¿cómo se pueden diferenciar dos objetos, ambos null
?
En segundo lugar, para inicializar de forma segura una variable en un entorno multiproceso, utilizar el patrón de una doble comprobación de bloqueo:
if (o == null) {
lock (lockObj) {
if (o == null) {
o = new Object();
}
}
}
Esto asegurará que otro hilo no lo ha inicializado el objeto y se puede utilizar para implementar el Patrón Singleton.
No puede bloquear en un valor nulo porque el CLR no tiene lugar para fijar la SyncBlock a, que es lo que permite que el CLR para sincronizar el acceso a los objetos de su elección mediante Monitor.Enter/salida (que es lo que lock
utiliza internamente)
+1: Esta es la respuesta más correcta. –
Por qué no C# permite un valor nulo para bloquearse?
Paul's answer es el único técnicamente correcto hasta el momento, así que lo aceptaría. Es porque los monitores en .NET usan el bloque de sincronización que está conectado a todos los tipos de referencia. Si tiene una variable que es null
, entonces no se está refiriendo a ningún objeto y eso significa que el monitor no tiene acceso a un bloque de sincronización utilizable.
¿Cómo puedo evitar esta condición de carrera?
El enfoque tradicional es bloquear una referencia de objeto que usted sabe que nunca será null
. Si se encuentra en una situación en la que esto no puede garantizarse, clasifico este enfoque no tradicional. Realmente no hay mucho más que pueda mencionar aquí a menos que describa con más detalle el escenario particular que puede conducir a los objetivos de bloqueo anulables.
la primera parte de su pregunta ya está contestada, pero me gustaría añadir algo de segunda parte de su pregunta.
es más sencillo de usar un objeto diferente para realizar el bloqueo, especialmente en esta condición. Esto también resuelve el problema de mantener los estados de múltiples objetos compartidos en una sección crítica, p. Ej. lista de empleados y lista de fotos de empleados.
Además, esta técnica también es útil cuando se tiene que adquirir cerradura de tipos primitivos por ejemplo, int o decimal, etc.
En mi opinión, si usted es utilizar esta técnica como todos los demás sugirió entonces que no es necesario para llevar a cabo null comprobar dos veces. p.ej.en la respuesta aceptada Cris ha usado la condición dos veces, lo que realmente no hace ninguna diferencia porque el objeto bloqueado es diferente de lo que realmente se está modificando, si está bloqueando un objeto diferente, entonces realizar la primera comprobación nula es inútil y perder la CPU .
Sugeriría la siguiente pieza de código;
object readonly syncRootEmployee = new object();
List<Employee> employeeList = null;
List<EmployeePhoto> employeePhotoList = null;
public void AddEmployee(Employee employee, List<EmployeePhoto> photos)
{
lock (syncRootEmployee)
{
if (employeeList == null)
{
employeeList = new List<Employee>();
}
if (employeePhotoList == null)
{
employeePhotoList = new List<EmployeePhoto>();
}
employeeList.Add(employee);
foreach(EmployeePhoto ep in photos)
{
employeePhotoList.Add(ep);
}
}
}
no puedo ver ninguna condición de carrera aquí si alguien más ver condición de carrera por favor, responda de los comentarios. Como puede ver en el código anterior, resuelve 3 problemas a la vez, uno no requiere verificación nula antes del bloqueo, segundo crea una sección crítica sin bloquear dos fuentes compartidas y el tercero bloquea más de un objeto causa bloqueos debido a la falta de atención al escribir código.
A continuación se muestra cómo utilizo los bloqueos en los tipos primitivos.
object readonly syncRootIteration = new object();
long iterationCount = 0;
long iterationTimeMs = 0;
public void IncrementIterationCount(long timeTook)
{
lock (syncRootIteration)
{
iterationCount++;
iterationTimeMs = timeTook;
}
}
public long GetIterationAvgTimeMs()
{
long result = 0;
//if read without lock the result might not be accurate
lock (syncRootIteration)
{
if (this.iterationCount > 0)
{
result = this.iterationTimeMs/this.iterationCount;
}
}
return result;
}
feliz :) enhebrar
- 1. ¿Por qué no se permite nulo para DateTime en C#?
- 2. ¿Por qué no se anula el valor nulo en C++?
- 3. ¿Por qué no se permite RVO al devolver un parámetro?
- 4. ¿Por qué C++ no permite estructuras anónimas?
- 5. ¿Por qué no se permite System.out.println (super)?
- 6. C# struct, ¿cómo asignar un valor nulo?
- 7. ¿Por qué/Cómo me permite .Net anular un Nullable <T> que es nulo?
- 8. ¿Por qué C# no permite un typeof como parámetro predeterminado?
- 9. ¿Por qué se permite T() = T()?
- 10. Por qué Windows no permite que WinSock se inicie mientras se hace pasar por otro usuario
- 11. ¿Por qué no puedo inyectar valor nulo con Ninjects ConstructorArgument?
- 12. ¿Por qué C++ no permite la amistad heredada?
- 13. ¿Qué condiciones ocasionan que NetworkStream.Write bloquee?
- 14. ¿Por qué Task.Delay() permite un retraso infinito?
- 15. Por qué crear instancias de variables con un valor nulo
- 16. ¿Por qué TFS no permite que se conecten múltiples colecciones con un solo controlador de compilación?
- 17. ¿Por qué no se permite este parámetro de plantilla predeterminado?
- 18. Comprueba que un valor entero sea nulo en C#
- 19. Por qué Python no permite guiones
- 20. removeFromSuperview hace que mi aplicación se bloquee
- 21. ¿Por qué no se permite que las clases selladas sean restricciones de tipo genérico?
- 22. qué puedo asignar un valor nulo a la unidad y por qué se convierten en()?
- 23. ¿Por qué C# le exige que escriba un cheque nulo cada vez que activa un evento?
- 24. ¿Por qué se permite un literal wchar_t vacío?
- 25. Regex.MatchData que devuelve nulo: ¿por qué no Opción [String]?
- 26. ¿Por qué C# permitiría un valor de enum no válido?
- 27. En c, ¿cómo hacer que un descriptor de archivo bloquee?
- 28. .NET Runtime Error hace que el proceso se bloquee. Pero no hay una excepción no controlada: ¿por qué? ¿Error CLR?
- 29. ¿Por qué usar (nulo) un caso válido en C#?
- 30. ¿Por qué se permite la cadena de caracteres y el compilador no permite int int?
¿Por qué no sólo tiene que utilizar un elemento que se ha inicializado estática y * siempre no es nulo * – zerkms
Como yo lo entiendo, es esencialmente nula nada. ¿Cómo se puede bloquear nada? En otras palabras, string myString = null declara una variable de tipo cadena, pero eso es todo lo que hay en ella - no existe como un objeto porque no tiene ningún valor. – Tim