2010-10-13 5 views
1

J'ai besoin d'un jeton d'authentification pour être thread et synchro. Le jeton expirera toutes les heures et il faudra donc en créer un nouveau et l'assigner à ma variable statique (TOKEN)Est-ce thread de code et de synchronisation en toute sécurité?

Est-ce que cela va faire l'affaire?

Merci,

public static volatile string TOKEN = string.Empty; 
    public static DateTime TOKEN_TIME = DateTime.Now; 
    private static readonly object syncRoot = new object(); 

    public static string Get() 
    { 
     if (!string.IsNullOrEmpty(TOKEN)) 
     { 
      if (!TokenIsValid()) 
      { 
       lock(syncRoot) 
        TOKEN = CreateNewToken(); 
      }     
     } 
     else 
     { 
      lock(syncRoot) 
       TOKEN = CreateNewToken(); 
     } 

     return TOKEN; 
    }   

Répondre

4

Non, ce code n'est pas thread-safe. Comme le verrou se produit à l'intérieur des instructions if, il est possible que deux threads créent un jeton à peu près en même temps. Considérez ce qui suit:

  • Discussion 1 entre else bloc
  • Discussion 1 donne à filetage 2
  • Discussion 2 pénètre dans else bloc
  • Discussion 2 prend verrou sur syncRoot, crée un nouveau jeton (jeton A) et l'attribue à TOKEN
  • Le thread 2 renvoie "jeton A".
  • Discussion 2 rendements à la discussion 1
  • Discussion 1 prend verrou sur syncRoot, crée un nouveau jeton (jeton B), et l'affecte à TOKEN
  • Discussion 1 retourne "jeton B".

Votre système utilise maintenant deux jetons différents qui ont été créés à des moments séparés, et Thread des références "jeton B".

Edit:
Vous pouvez rendre votre code threadsafe en prenant un verrou avant de vérifier même le jeton. L'exemple ci-dessous verrouille tous les appels au Get(), donc il ne créera pas deux jetons (presque) en même temps que votre code. Il existe également d'autres modèles de verrouillage que vous pouvez utiliser, dont certains peuvent donner de meilleures performances.

public static string Get() 
{ 
    lock(syncRoot) 
    { 
     if (string.IsNullOrEmpty(TOKEN) || !TokenIsValid()) 
      TOKEN = CreateNewToken(); 
     return TOKEN; 
    } 
} 
+0

Le même scénario peut se produire pour la branche 'if' également. Et comme une solution, je proposerais d'envelopper tout le corps 'Get()' avec un seul verrou. – zerkms

+2

Un exemple de meilleure performance (tout en utilisant simplement 'lock') consiste à utiliser le double-verrouillage: http://en.wikipedia.org/wiki/Double-checked_locking. Lire à travers les mises en garde là, cependant. –

Questions connexes