Me acabo de dar cuenta de que en algún lugar de mi código tengo la declaración de devolución dentro de la cerradura y en algún momento afuera. ¿Cuál es el mejor?
1)
void example()
{
lock (mutex)
{
//...
}
return myData;
}
2)
void example()
{
lock (mutex)
{
//...
return myData;
}
}
¿Cuál debo usar?
c#
.net
multithreading
mutex
Patrick Desjardins
fuente
fuente
Respuestas:
Esencialmente, lo que hace que el código sea más simple. El único punto de salida es un buen ideal, pero no doblaría el código solo para lograrlo ... Y si la alternativa es declarar una variable local (fuera de la cerradura), inicializarla (dentro de la cerradura) y luego devolverlo (fuera de la cerradura), luego diría que un simple "retorno foo" dentro de la cerradura es mucho más simple.
Para mostrar la diferencia en IL, permite codificar:
(tenga en cuenta que felizmente argumentaría que
ReturnInside
es un bit más simple / más limpio de C #)Y mira el IL (modo de lanzamiento, etc.):
Entonces, en el nivel de IL son [dar o tomar algunos nombres] idénticos (aprendí algo ;-p). Como tal, la única comparación sensata es la ley (altamente subjetiva) del estilo de codificación local ... Prefiero la
ReturnInside
simplicidad, pero tampoco me entusiasmaría.fuente
ret
dentro de una.try
región.No hace ninguna diferencia; ambos están traducidos a lo mismo por el compilador.
Para aclarar, cualquiera se traduce efectivamente a algo con la siguiente semántica:
fuente
Definitivamente pondría la devolución dentro de la cerradura. De lo contrario, corre el riesgo de que otro subproceso ingrese al bloqueo y modifique su variable antes de la declaración de devolución, por lo tanto, la persona que llama original recibe un valor diferente al esperado.
fuente
Depende,
Voy a ir contra la corriente aquí. En general, volvería dentro de la cerradura.
Por lo general, la variable mydata es una variable local. Soy aficionado a declarar variables locales mientras las inicializo. Raramente tengo los datos para inicializar mi valor de retorno fuera de mi candado.
Entonces su comparación es realmente defectuosa. Si bien, idealmente, la diferencia entre las dos opciones sería la que había escrito, lo que parece indicar el caso 1, en la práctica es un poco más feo.
vs.
Creo que el caso 2 es considerablemente más fácil de leer y más difícil de arruinar, especialmente para fragmentos cortos.
fuente
Si cree que la cerradura exterior se ve mejor, pero tenga cuidado si termina cambiando el código a:
Si es necesario invocar f () con el candado retenido, entonces obviamente debe estar dentro del candado, por lo que mantener los retornos dentro del candado para mantener la coherencia tiene sentido.
fuente
Para lo que vale, la documentación en MSDN tiene un ejemplo de regreso desde el interior de la cerradura. De las otras respuestas aquí, parece ser una IL bastante similar, pero, para mí, parece más seguro regresar desde el interior de la cerradura porque entonces no corres el riesgo de que una variable de retorno sea sobrescrita por otro hilo.
fuente
Para facilitar a los demás desarrolladores la lectura del código, sugeriría la primera alternativa.
fuente
lock() return <expression>
declaraciones siempre:1) entrar cerradura
2) crea una tienda local (segura para subprocesos) para el valor del tipo especificado,
3) llena la tienda con el valor devuelto por
<expression>
,4) cerradura de salida
5) devolver la tienda.
Significa que el valor, devuelto por la declaración de bloqueo, siempre "cocido" antes de la devolución.
No te preocupes
lock() return
, no escuches a nadie aquí))fuente
Nota: Creo que esta respuesta es objetivamente correcta y espero que también sea útil, pero siempre estoy feliz de mejorarla en base a comentarios concretos.
Para resumir y complementar las respuestas existentes:
La respuesta aceptada muestra que, independientemente de la forma de sintaxis que elija en su código C # , en el código IL, y por lo tanto en tiempo de ejecución,
return
no sucede hasta después de que se libera el bloqueo.return
interior dellock
bloque por lo tanto, estrictamente hablando, tergiversa el flujo de control [1] , es sintácticamente conveniente porque obvia la necesidad de almacenar el valor de retorno en un auxiliar. variable local (declarada fuera del bloque, para que pueda usarse con unreturn
fuera del bloque) - vea la respuesta de Edward KMETT .Por separado, y este aspecto es incidental a la pregunta, pero aún puede ser de interés ( la respuesta de Ricardo Villamil intenta abordarlo, pero creo que es incorrecto), combinando una
lock
declaración con unareturn
declaración, es decir, obteniendo valorreturn
en un bloque protegido de acceso concurrente: solo "protege" significativamente el valor devuelto en el alcance de la persona que llama si realmente no necesita protección una vez obtenido , lo que se aplica en los siguientes escenarios:Si el valor devuelto es un elemento de una colección que solo necesita protección en términos de agregar y eliminar elementos, no en términos de modificaciones de los propios elementos y / o ...
... si el valor que se devuelve es una instancia de un tipo de valor o una cadena .
En cualquier otro caso, el bloqueo debe ser realizado por la persona que llama , no (solo) dentro del método.
[1] Theodor Zoulias señala que esto es técnicamente cierto también para la colocación
return
en el interiortry
,catch
,using
,if
,while
,for
, ... declaraciones; sin embargo, es el propósito específico de lalock
declaración lo que probablemente invitará al escrutinio del verdadero flujo de control, como lo demuestra esta pregunta que se hizo y recibió mucha atención.[2] Al acceder a una instancia de tipo de valor, invariablemente se crea una copia local en la pila de subprocesos; aunque las cadenas son instancias de tipo de referencia técnica, se comportan efectivamente como instancias de tipo de valor similar.
fuente
lock
y derivando el significado de la ubicación de la declaración de devolución. Que es una discusión no relacionada con esta pregunta en mi humilde opinión. También encuentro el uso de "tergiversaciones" bastante inquietante. Si volver de unlock
tergiversa el flujo de control, entonces el mismo puede decirse para el retorno de unatry
,catch
,using
,if
,while
,for
, y cualquier otra construcción de la lengua. Es como decir que C # está plagado de tergiversaciones de flujo de control. Jesús ...try
,if
, ... yo personalmente no tienden a pensar en ello, pero en el contexto delock
, en concreto, se planteó la cuestión para mí - y si no se plantea también para los demás, nunca habría hecho esta pregunta , y la respuesta aceptada no habría ido demasiado lejos para investigar el verdadero comportamiento.