2009-08-10 8 views
12

ok, è un po 'più complicato della domanda.Ho bisogno di creare una variabile statica thread-safe in C# .Net

class A 
{ 
    static int needsToBeThreadSafe = 0; 

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

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

ora ho bisogno che tra M1() e M2() chiama soggiorni 'needsToBeThreadSafe' thread-safe.

+1

Vuoi dire che si desidera che le chiamate a M1() e M2() essere atomica? – Bombe

+2

Cosa intendi per "rimane thread-safe"? –

risposta

18

Che cosa si potrebbe tentare di chiedere è la [ThreadStatic] attributo. Se si desidera che ogni thread che utilizza la classe A di avere un proprio valore separata di needsToBeThreadSafe allora non vi resta che decorare quel campo con il [ThreadStatic] attributo.

Per ulteriori informazioni, fare riferimento allo MSDN documentation for ThreadStaticAttribute.

+0

Immagino che anche tutti gli altri abbiano ragione, ma per la mia situazione funziona perfettamente. – Storm

+5

OK, ma ThreadStatic è qualcosa di diverso rispetto a ThreadSafe. –

+0

In qualche modo, mi sono appena reso conto che quello che è veramente dopo è un valore che non è condiviso tra Thread. Inoltre, ThreadStatic ** è ** thread-safe poiché in realtà non ci sono due thread che accedono alla stessa variabile (anche se sembra che siano). – 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 dovrebbe essere * readonly *, solo precauzione ... l'armadietto – ipavlu

8

Avete due scelte: il più facile dato il vostro codice presentato è la parola chiave volatile. dichiarare needsToBeThreadSafe come static volatile int e ciò garantirà che qualsiasi thread che fa riferimento a tale variabile riceverà la copia "più recente" e la variabile non verrà memorizzata nella cache all'interno del codice.

Detto questo, se si vuole garantire più in generale che M1() e M2() eseguire "atomico" (o almeno esclusivamente l'uno dall'altro), poi si desidera utilizzare un lock. La sintassi è più pulita con un "blocco di blocco", in questo modo:

private static object locker = new Object(); 

//.. 

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

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

Come al quale approccio adottare, che sta a voi e dovrebbe essere determinata dal codice. Se tutto ciò di cui hai bisogno è garantire che l'assegnazione di un membro venga propagata a tutti i thread e non sia memorizzata nella cache, la parola chiave volatile è più semplice e farà bene il lavoro. Se è oltre questo, potresti voler andare con lo lock.

+0

deve essere * di sola lettura *, solo precauzione ... – ipavlu

2

Suono come se fosse necessario un membro Volatile.

static volatile int needsToBeThreadSafe = 0; 
+0

Era il commento del 2009, ma al giorno d'oggi è meglio evitare volatili, visto che ha effetti collaterali ... – ipavlu

2

È inoltre possibile utilizzare il ReaderWriterLockSlim, che è più efficiente per più letture e meno scrive:

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 dovrebbe essere * readonly *, solo precauzione ... – ipavlu

2

Per cominciare sono d'accordo con le risposte utilizzando lock(), che è il modo più sicuro.

Ma esiste un approccio più minimalista, il codice di esempio mostra solo le dichiarazioni singole utilizzando needsToBeThreadSafe e dal int è atomico è sufficiente per impedire la memorizzazione nella cache dal compilatore utilizzando volatile:

class A 
{ 
    static volatile int needsToBeThreadSafe = 0; 

} 

Ma se si serve needToBeThreadSafe per essere 'ThreadSafe' su più istruzioni, utilizzare un lock.

+0

Era la risposta del 2009, ma al giorno d'oggi, sarebbe meglio usare in risposta il blocco suggerito che volatile come volatile ha effetti collaterali, che tendono a creare problemi facilmente ... – ipavlu

20

Come su:

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

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

AMO QUESTO, è sicuro ed è super veloce, VERGOGNA ha ottenuto solo 4 upvotes (il mio incluso) dopo la metà decade! – ipavlu

Problemi correlati