2009-08-10 7 views
12

ok, c'est un peu plus compliqué que la question.Je dois créer une variable statique Thread-safe en C# .Net

class A 
{ 
    static int needsToBeThreadSafe = 0; 

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

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

maintenant je rechercherai qu'entre M1() et M2() appelle les séjours 'needsToBeThreadSafe' thread-safe.

+1

Vous voulez dire que vous voulez que les appels à M1() et M2() être atomique? – Bombe

+2

Qu'entendez-vous par "reste thread safe"? –

Répondre

18

Ce que vous pourriez essayer de demander est sur l'attribut [ThreadStatic]. Si vous voulez que chaque fil qui utilise la classe A d'avoir sa propre valeur séparée de needsToBeThreadSafe alors vous avez juste besoin de décorer ce champ avec l'attribut [ThreadStatic].

Pour plus d'informations, reportez-vous au MSDN documentation for ThreadStaticAttribute.

+0

Je suppose que tout le monde avait aussi raison, mais pour ma situation cela fonctionne parfaitement. – Storm

+5

OK, mais ThreadStatic est autre chose que ThreadSafe. –

+0

D'une manière ou d'une autre, je viens de me rendre compte que ce qu'il cherche réellement est une valeur qui n'est pas partagée entre Threads. En outre, ThreadStatic ** est ** thread-safe car en réalité, deux threads n'accèdent pas à la même variable (même si cela semble être le cas). – 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 devrait être * readonly *, juste précaution ... – ipavlu

8

Vous avez deux choix: le mot-clé est le plus facile volatile donné votre code présenté. déclarer needsToBeThreadSafe comme static volatile int et cela garantira que n'importe quel thread qui référence cette variable obtiendra la "dernière" copie, et la variable ne sera pas mise en cache dans votre code.

Cela dit, si vous voulez vous assurer que plus généralement M1() et M2() execute « atomiquement » (ou du moins exclusivement les uns des autres), alors vous voulez utiliser un lock. La syntaxe est propre avec un « bloc de verrouillage », comme ceci:

private static object locker = new Object(); 

//.. 

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

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

Quant à l'approche à adopter, qui est à vous et doivent être déterminées par le code. Si tout ce dont vous avez besoin est de vous assurer qu'une affectation de membre est propagée à tous les threads et n'est pas mise en cache, le mot-clé volatile est plus simple et fera l'affaire correctement. Si c'est au-delà, vous voudrez peut-être aller avec le lock.

+0

locker devrait être * readonly *, juste précaution ... – ipavlu

2

Vous avez besoin d'un membre Volatile.

static volatile int needsToBeThreadSafe = 0; 
+0

C'était le commentaire de 2009, mais de nos jours il vaut mieux éviter les volatiles, car il a des effets secondaires ... – ipavlu

2

Vous pouvez également utiliser la ReaderWriterLockSlim, qui est plus efficace pour plusieurs lectures et moins écrit:

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 devrait être * readonly *, juste précaution ... – ipavlu

2

Pour commencer, je suis d'accord avec les réponses en utilisant lock(), qui est le moyen le plus sûr.

Mais il existe une approche plus minimaliste, votre exemple de code ne montre que des déclarations simples à l'aide needsToBeThreadSafe et depuis int est atomique il vous suffit d'empêcher la mise en cache par le compilateur à l'aide volatile:

class A 
{ 
    static volatile int needsToBeThreadSafe = 0; 

} 

Mais si vous needToBeThreadSafe doit être 'ThreadSafe' sur plusieurs instructions, utilisez un verrou.

+0

C'était la réponse de 2009, mais de nos jours, il serait préférable d'utiliser dans la réponse suggestion verrouillée que volatile comme volatile a des effets secondaires, qui ont tendance à créer facilement des problèmes ... – ipavlu

20

Comment A propos:

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

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

J'AIME CELUI, est sûr et est super rapide, SHAME il a seulement 4 upvotes (le mien inclus) après une demi-décennie! – ipavlu

Questions connexes