2009-08-10 22 views
12

bien, es un poco más complicado que la pregunta.Necesito crear una variable estática Thread-safe en C# .Net

class A 
{ 
    static int needsToBeThreadSafe = 0; 

    public static void M1() 
    { 
    needsToBeThreadSafe = RandomNumber(); 
    } 

    public static void M2() 
    { 
    print(needsToBeThreadSafe); 
    } 
} 

ahora requieren que entre M1() y M2() llama estancias 'needsToBeThreadSafe' hilo de seguridad.

+1

¿Quiere decir que desea que las llamadas a M1() y M2() ser atómicas? – Bombe

+2

¿Qué quiere decir con "stay thread safe"? –

Respuesta

18

Lo que podría estar tratando de preguntar acerca es el [ThreadStatic] atributo. Si desea que cada hilo que se utiliza la clase A tener su propio valor independiente de needsToBeThreadSafe continuación, sólo tiene que decorar ese campo con el atributo [ThreadStatic].

Para obtener más información, consulte MSDN documentation for ThreadStaticAttribute.

+0

Supongo que todos los demás también tenían razón, pero para mi situación, esto funciona a la perfección. – Storm

+5

OK, pero ThreadStatic es algo más que ThreadSafe. –

+0

De alguna manera, me acabo de dar cuenta de que lo que realmente busca es un valor que no se comparte entre los hilos. Además, ThreadStatic ** es ** seguro para subprocesos ya que en realidad no hay dos subprocesos que accedan a la misma variable (aunque parezca que sí). – paracycle

4
class A 
{ 
    static int needsToBeThreadSafe = 0; 
    static object statObjLocker = new object(); 

    public static void M1() 
    { 
     lock(statObjLocker) 
     { 
      needsToBeThreadSafe = RandomNumber(); 
     } 
    } 

    public static void M2() 
    { 
     lock(statObjLocker) 
     { 
      print(needsToBeThreadSafe); 
     } 
    } 
} 
+0

statObjLocker debe ser * readonly *, solo precaución ... – ipavlu

8

Usted tiene dos opciones: la más fácil dada su código que se presenta es la palabra clave volatile. declare needsToBeThreadSafe como static volatile int y eso garantizará que cualquier hilo que haga referencia a esa variable obtendrá la "última" copia, y la variable no se almacenará en caché dentro de su código.

Dicho esto, si usted quiere asegurarse de manera más general que M1() y M2() ejecutar "atómicamente" (o al menos exclusivamente el uno del otro), entonces usted desea utilizar un lock. La sintaxis es más limpia con un "bloque de bloqueo", como este:

private static object locker = new Object(); 

//.. 

public static void M1() 
{ 
    lock(locker) 
    { 
     //..method body here 
    } 
} 

public static void M2() 
{ 
    lock(locker) 
    { 
     //..method body here 
    } 
} 

En cuanto a qué postura tomar, eso depende de usted y debe ser determinado por el código. Si todo lo que necesita es garantizar que una asignación de miembro se propague a todos los hilos y no se almacene en caché, entonces la palabra clave volatile es más simple y hará el trabajo bien. Si está más allá de eso, es posible que desee ir con el lock.

+0

Locker debe ser * readonly *, solo precaución ... – ipavlu

2

Parece que necesita un miembro Volatile.

static volatile int needsToBeThreadSafe = 0; 
+0

Fue un comentario de 2009, pero hoy en día es mejor evitar la volatilidad, ya que tiene efectos secundarios ... – ipavlu

2

También puede utilizar el ReaderWriterLockSlim, que es más eficiente para varias lecturas y escrituras menos:

static int needsToBeThreadSafe = 0; 
static System.Threading.ReaderWriterLockSlim rwl = new System.Threading.ReaderWriterLockSlim(); 

public static void M1() 
{ 
    try 
    { 
     rwl.EnterWriteLock(); 
     needsToBeThreadSafe = RandomNumber(); 
    } 
    finally 
    { 
     rwl.ExitWriteLock(); 
    } 

} 

public static void M2() 
{ 
    try 
    { 
     rwl.EnterReadLock(); 
     print(needsToBeThreadSafe); 
    } 
    finally 
    { 
     rwl.ExitReadLock(); 
    } 
} 
+0

rwl debe ser * readonly *, solo precaución ... – ipavlu

2

Para empezar estoy de acuerdo con las respuestas usando lock(), que es la forma más segura.

Pero existe un enfoque más minimalista, el código de ejemplo solamente se presentan los mensajes individuales utilizando needsToBeThreadSafe y desde int es atómica sólo es necesario para evitar el almacenamiento en caché por el compilador utilizando volátil:

class A 
{ 
    static volatile int needsToBeThreadSafe = 0; 

} 

Pero si necesita needsToBeThreadSafe para ser 'ThreadSafe' en varias declaraciones, use un candado.

+0

Fue en 2009 la respuesta, pero hoy en día, sería mejor utilizar en respuesta a bloqueo sugerido que volátil, ya que los efectos secundarios tienen efectos secundarios volátiles, que tienden a crear problemas fácilmente ... – ipavlu

20

¿Qué tal:

public static void M1() 
{ 
    Interlocked.Exchange(ref needsToBeThreadSafe, RandomNumber()); 
} 

public static void M2() 
{ 
    print(Interlocked.Read(ref needsToBeThreadSafe)); 
} 
+0

ME ENCANTA ESTE, es seguro y es superrápido, ¡MIERDA, recibí solo 4 votaciones ascendentes (la mía incluida) después de media década! – ipavlu

Cuestiones relacionadas