c# - ¿Cómo funciona el atributo ThreadStatic?
(3)
¿Cómo funciona el atributo [ThreadStatic]?
Puede pensar que el campo marcado con ThreadStatic está unido a un hilo y su duración es comparable a la vida útil de un hilo.
Por lo tanto, en el pseudocódigo, ThreadStatic
es similar (por semántica) a tener una clave-valor asociada a un hilo:
Thread.Current["MyClass.myVariable"] = 1;
Thread.Current["MyClass.myvariable"] += 1;
pero la sintaxis es un poco más fácil:
class MyClass {
[ThreadStatic]
static int myVariable;
}
// .. then
MyClass.myVariable = 1;
MyClass.myVariable += 1;
¿Qué pasa si lo pones en un miembro no estático?
Yo creo que es ignorado
class A {
[ThreadStatic]
public int a;
}
[Test]
public void Try() {
var a1 = new A();
var a2 = new A();
a1.a = 5;
a2.a = 10;
a1.a.Should().Be.EqualTo(5);
a2.a.Should().Be.EqualTo(10);
}
Además, vale la pena mencionar que ThreadStatic
no requiere ningún mecanismo de sincronización en comparación con los campos estáticos normales (porque el estado no se comparte).
¿Cómo funciona el atributo [ThreadStatic]
? Supuse que el compilador emitiría alguna IL para rellenar / recuperar el valor en el TLS, pero al mirar un desmontaje parece que no lo hace a ese nivel.
Como seguimiento, ¿qué sucede si lo pones en un miembro no estático? Tuvimos un desarrollador que cometió ese error y el compilador ni siquiera ofrece una advertencia.
Actualizar
Segunda pregunta respondida aquí: ThreadStatic modificado con Static C #
El [ThreadStatic] crea versiones aisladas de la misma variable en cada hilo.
Ejemplo:
[ThreadStatic] public static int i; // Declaration of the variable i with ThreadStatic Attribute.
public static void Main()
{
new Thread(() =>
{
for (int x = 0; x < 10; x++)
{
i++;
Console.WriteLine("Thread A: {0}", i); // Uses one instance of the i variable.
}
}).Start();
new Thread(() =>
{
for (int x = 0; x < 10; x++)
{
i++;
Console.WriteLine("Thread B: {0}", i); // Uses another instance of the i variable.
}
}).Start();
}
La semántica de implementación del hilo estático está por debajo del nivel IL, en el compilador jit .NET. Los compiladores que emiten a IL como VB.NET y C # no necesitan saber nada sobre Win32 TLS para emitir código IL que pueda leer y escribir una variable que tenga el atributo ThreadStatic. No hay nada especial acerca de la variable en lo que C # conoce: es solo un lugar para leer y escribir cosas. El hecho de que tenga un atributo no tiene ninguna consecuencia para C #. C # solo necesita saber para emitir instrucciones de lectura o escritura de IL para ese nombre de símbolo.
El "levantamiento pesado" es realizado por el CLR central que es responsable de hacer que IL funcione en una arquitectura de hardware particular.
Eso también explicaría por qué poner el atributo en un símbolo inapropiado (no estático) no obtiene una reacción del compilador. El compilador no sabe qué semántica especial requiere el atributo. Las herramientas de análisis de código como FX / Cop, sin embargo, deberían saberlo.
Otra forma de verlo: CIL define un conjunto de ámbitos de almacenamiento: almacenamiento estático (global), almacenamiento de miembros y almacenamiento de pila. TLS no está en esa lista, muy probablemente porque TLS no necesita estar en esa lista. Si las instrucciones de lectura y escritura de IL son suficientes para acceder a TLS cuando el símbolo está etiquetado con un atributo TLS, ¿por qué IL debe tener alguna representación o tratamiento especial para TLS? No es necesario.