11
votes

J'ai besoin de créer une variable statique de fil-sécurité en C # .NET

OK, c'est un peu plus compliqué que la question.

class A
{
   static int needsToBeThreadSafe = 0;

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

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


2 commentaires

Vous voulez dire que vous voulez que les appels à M1 () et M2 () soient atomiques?


Qu'entendez-vous par «Séjours en sécurité du fil»?


7 Réponses :


4
votes
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 commentaires

8
votes

Vous avez deux choix: les plus simples que votre code présenté est le mot clé volatile . Déclare NeedstobetHreadsafe comme statique volatil int et qui garantira que tout fil qui fait référence à la variable obtiendra la "dernière" copie et la variable ne sera pas mise en cache dans votre code. .

qui étant dit, si vous voulez mieux vous assurer que m1 () et m2 () exécuter "atomiquement" (ou au moins exclusivement l'un de l'autre) , alors vous voulez utiliser un verrouillage . La syntaxe la plus propre est avec un "bloc de verrouillage", comme celui-ci: xxx

sur quelle approche à prendre, c'est à vous et doit être déterminé par le code. Si tout ce dont vous avez besoin est de vous assurer qu'un assignation de membre est propagé à tous les threads et n'est pas mis en cache, le mot clé volatile est plus simple et fera le travail tout à fait. Si c'est au-delà de cela, vous voudrez peut-être aller avec le verrouillage .


0 commentaires

2
votes

Son comme vous avez besoin d'un volatile membre.

static volatile int needsToBeThreadSafe = 0;


1 commentaires

C'était un commentaire de 2009, mais de nos jours, il est préférable d'éviter de volatiles, car il a des effets secondaires ...



20
votes

Qu'est-ce que vous essayez d'essayer de poser une question sur l'attribut [ threadstatic ]. Si vous voulez chaque fil qui utilise la classe A pour avoir sa propre valeur distincte de NeedstobetHreadsafe alors vous avez juste besoin de décorer ce champ avec l'attribut [ threadstatic ].

Pour plus d'informations, reportez-vous au Documentation MSDN pour threadstaticattribute .


5 commentaires

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


D'une manière ou d'une autre, je viens de réaliser que ce qu'il est réellement après une valeur qui n'est pas partagée entre les threads. En outre, ThreadStatic est Safe-Safe-Safe car il n'y a même pas deux threads accéder à la même variable (même s'il semble qu'ils sont).


@paraccler: Bon travail pour répondre à la question, mais éliminer le potentiel de conflit en créant des copies locales signifie que ceci est, par définition, pas de "fil sûr". Bien que ce ne soit pas "dangereux", la sécurité du fil signifie qu'il gère correctement plusieurs threads traitant de la ressource la même ; Je ne dirais pas que la copie de la ressource est un moyen de le faire.


I DO Obtenez vos points et je ne veux pas étendre inutilement la conversation, mais ma compréhension du "thread-coffre-fort" est si un morceau de code est sûr de fonctionner simultanément sous plusieurs threads. "Storage local" est une implémentation triviale de cette définition et pourrait ne pas répondre à vos besoins si vous avez réellement besoin de données partagées. Si ce dont vous avez besoin est de multiples threads d'exécution sans threads sur les pieds de chacun, et le "stockage local de thread-local" répond à vos besoins, c'est la voie à suivre. En outre, l'article Wikipedia ( en.wikipedia.org/wiki/Trhead_Safety ) semble être d'accord avec moi.


La chose ici est que cela rend une variable statique A Variable de fil-locale , mais qui reste un membre de l'ensemble de fil-coffre-fort :).



2
votes

Vous pouvez également utiliser le 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 commentaires

2
votes

Pour commencer avec je suis d'accord avec les réponses à l'aide de verrouillage () code>, c'est la manière la plus sûre.

Il existe une approche plus minimaliste, votre code d'exemple ne montre que des déclarations simples en utilisant NeedstobetHreadsafe CODE> et puisque INT CODE> FORT> est atomique, il vous suffit d'empêcher la mise en cache par le compilateur à l'aide de volatiles: P>

class A
{
   static volatile int needsToBeThreadSafe = 0;

}


1 commentaires

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



23
votes

Que diriez-vous:

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

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


1 commentaires

J'adore celui-ci, c'est sûr et est super rapide, la honte qu'elle n'avait que 4 upvotes (mienne incluses) après une demi-décennie!