2010-03-30 4 views
2

Je développe une application Web de formulaires ASP.NET à l'aide de C#. J'ai une méthode qui crée une nouvelle commande pour un client. Cela ressemble à ceci;Méthode de thread de verrouillage ASP.NET

private string CreateOrder(string userName) { 
     // Fetch current order 
     Order order = FetchOrder(userName); 
     if (order.OrderId == 0) { 
      // Has no order yet, create a new one 
      order.OrderNumber = Utility.GenerateOrderNumber(); 
      order.Save(); 
     } 
     return order; 
    } 

Le problème est ici, il est possible que 1 client dans deux requêtes (threads) pourrait provoquer cette méthode à appeler deux fois, tandis qu'un autre fil est également à l'intérieur de cette méthode. Cela peut entraîner la création de deux commandes.

Comment puis-je verrouiller correctement cette méthode, afin qu'elle ne puisse être exécutée que par un thread à la fois par client?

J'ai essayé;

Mutex mutex = null; 
    private string CreateOrder(string userName) { 
     if (mutex == null) { 
      mutex = new Mutex(true, userName); 
     } 
     mutex.WaitOne(); 
     // Code from above 
     mutex.ReleaseMutex(); 
     mutex = null; 
     return order; 
    } 

Cela fonctionne, mais dans certains cas, il se bloque sur WaitOne et je ne sais pas pourquoi. Y at-il une erreur, ou devrais-je utiliser une autre méthode pour verrouiller?

Merci

Répondre

1

Passez le false pour initiallyOwned dans le mutex ctor. Si vous créez le mutex et que vous le possédez initialement, vous devez appeler à nouveau le ReleaseMutex.

1

Vous devriez toujours enfin essayer lors de la libération mutex. Aussi, assurez-vous que la clé est correcte (userName)

Mutex mutex = null; 
private string CreateOrder(string userName) { 
    mutex = mutex ?? new Mutex(true, userName); 
    mutex.WaitOne(); 
    try{ 
    // Code from above 
    }finally{ 
    mutex.ReleaseMutex(); 
    } 
    mutex = null; 
    return order; 
} 
+0

Merci, c'est en effet une erreur de ne pas ajouter l'essai/enfin. Mais malheureusement, ce n'est pas la solution au problème. – Peter

0

À moins que je me manque quelque chose, vous ne pouvez pas simplement utiliser une serrure régulière?

private object _locker = new object(); 

private string CreateOrder(string userName) 
{ 
    lock(_locker) 
    { 
     // Fetch current order 
     Order order = FetchOrder(userName); 
     if (order.OrderId == 0) 
     { 
      // Has no order yet, create a new one 
      order.OrderNumber = Utility.GenerateOrderNumber(); 
      order.Save(); 
     } 
     return order; 
    } 
} 
+0

C'est ce qui m'est venu à l'esprit aussi, peut-être que quelqu'un peut nous éclairer sur la différence entre un mutex et une serrure? Je suppose qu'un verrou est vraiment juste un mutex sous la surface, et vous utilisez un mutex spécifiquement pour obtenir plus de fonctionnalités, mais c'est juste une supposition ... – NibblyPig

+0

Salut, peut-être que je devrais verrouiller. L'idée derrière l'utilisation du Mutex était que j'ai seulement besoin de verrouiller la méthode par nom d'utilisateur. Je voulais accomplir cela avec un Mutex nommé. – Peter

+0

C'est global - "Une primitive de synchronisation qui peut également être utilisée pour la synchronisation interprocess". Vous pouvez l'utiliser entre des processus sur le même PC - par ex. S'assurer qu'une application ne démarre qu'une seule fois ... –

1

Dans votre code, vous créez paresseusement le mutex. Cela conduit à des conditions de course.
E.g. il peut arriver que le mutex ne soit que partiellement construit lorsque vous appelez WaitOne() depuis un autre thread.
Il peut également arriver que vous créiez deux instances de mutex.
etc ...

Vous pouvez éviter cela en créant l'instance avec impatience - c'est-à-dire comme dans le code de Michael. (Assurez-vous de l'initialiser à un état sans appartenance.)

Mutex est une primitive de synchronisation au niveau du noyau - elle est plus coûteuse que Monitor (c'est ce que lock utilise).

+1

Vous avez raison, je n'ai pas pensé à ça. Cela conduit au même problème que j'essayais d'éviter (les ordres partiellement construits) ... Merci à tous pour les réponses. – Peter

0

J'ai toujours évité de verrouiller une application Web: laissez le serveur Web gérer les threads et créer une détection en double. Que pensez-vous que vous obtiendrez en verrouillant sur le CreateOrder?

Il me semble que vous pouvez éviter de créer deux ordres simultanément, mais vous allez toujours vous retrouver avec deux ordres créés.

0

Il est plus facile de faire ceci:

définissent une classe quelque part comme ceci:

public class MyLocks { 
    public static object OrderLock; 
    static MyLocks() { 
     OrderLock = new object(); 
    } 
} 

puis lors de l'utilisation de la serrure faire:

lock(MyLocks.OrderLock) { 
    // put your code here 
} 

Son pas très compliqué alors.Sa légèreté permet de définir des verrous pour n'importe quel but car ce ne sont que de très petits objets en mémoire qui sont vivants sur plusieurs threads.

Questions connexes