2010-04-23 12 views
2

J'ai quelques enregistrements, que je veux enregistrer à la base de données de manière asynchrone. Je les organise en lots, puis les envoie. Au fil du temps, les lots sont traités.. NET 3.5 C# n'offre pas ce dont j'ai besoin pour le verrouillage: Count async enregistre jusqu'à 0 à nouveau

En attendant, l'utilisateur peut travailler. Il y a certaines opérations critiques, que je veux verrouiller, alors que tout lot de sauvegarde est encore en cours d'exécution de manière asynchrone.

La sauvegarde est faite en utilisant un TableServiceContext et la méthode .BeginSave() - mais je pense que cela ne devrait pas être pertinent. Ce que je veux faire est quand une sauvegarde asynchrone est commencée, augmentez un nombre de verrous, et quand elle se termine, diminuez le nombre de verrous de sorte qu'il sera zéro dès que tous ont fini. Je veux verrouiller l'opération critique tant que le compte n'est pas nul. En outre, je souhaite qualifier l'objet métier lock-by, par exemple.

Je n'ai pas trouvé de méthode de verrouillage .NET 3.5 C#, qui satisfait à cette exigence. Un sémaphore ne contient pas de méthode à vérifier, si le compte est 0. Sinon, un sémaphore avec un nombre maximal illimité ferait l'affaire.

Répondre

3

En fait, le Semapharene ont une méthode de vérification pour voir si le compte est égal à zéro. Utilisez la méthode WaitOne avec un délai d'attente nul. Il retournera une valeur indiquant si le sémaphore a été acquis. Si elle renvoie false alors elle n'a pas été acquise ce qui implique que son compte est nul.

var s = new Semaphore(5, 5); 

while (s.WaitOne(0)) 
{ 
    Console.WriteLine("acquired"); 
} 

Console.WriteLine("no more left to acquire"); 
0

Quel est le but du nombre de verrous si la seule logique implique si oui ou non la valeur est différente de zéro?

Si vous voulez faire sur une base type par type, vous pouvez utiliser cette approche:

public class BusinessObject1 
{ 
    private static readonly object lockObject = new object(); 

    public static object SyncRoot { get { return lockObject; } } 
} 

(suivant le même modèle pour d'autres objets métier)

Si vous puis entourez vos économies et vos opérations critiques dans un bloc comme celui-ci:

lock(BusinessObject1.SyncRoot) 
{ 
    // do work 
} 

Vous ferez des économies et les opérations critiques de tâches mutuellement exclusives.

Puisque vous le vouliez granulaire, vous pouvez en cascade les serrures comme ceci:

lock(BusinessObject1.SyncRoot) 
lock(BusinessObject2.SyncRoot) 
lock(BusinessObject3.SyncRoot) 
{ 
    // do work 
} 
1

Je présume que lorsque vous dites verrouiller l'utilisateur sur, il n'est pas un « verrouillage » littérale alors que les opérations sont terminées car cela bloquerait le thread d'interface utilisateur et geler l'application lorsque le verrou a été rencontré. Je suppose que vous voulez dire que certains états peuvent être vérifiés afin que les contrôles de l'interface utilisateur puissent être désactivés/activés.

Quelque chose comme le code suivant pourrait être utilisé qui est libre de verrouillage:

public class BusyState 
{ 
    private int isBusy; 

    public void SignalTaskStarted() 
    { 
     Interlocked.Increment(ref isBusy); 
    } 

    public void SignalTaskFinished() 
    { 
     if (Interlocked.Decrement(ref isBusy) < 0) 
     { 
      throw new InvalidOperationException("No tasks started."); 
     } 
    } 

    public bool IsBusy() 
    { 
     return Thread.VolatileRead(ref isBusy) > 0; 
    } 
} 

public class BusinessObject 
{ 
    private readonly BusyState busyState = new BusyState(); 

    public void Save() 
    { 
     //Raise a "Started" event to disable UI controls... 

     //Start a few async tasks which call CallbackFromAsyncTask when finished. 

     //Start task 1 
     busyState.SignalTaskStarted(); 

     //Start task 2 
     busyState.SignalTaskStarted(); 

     //Start task 3 
     busyState.SignalTaskStarted(); 
    } 

    private void CallbackFromAsyncTask() 
    { 
     busyState.SignalTaskFinished(); 

     if (!busyState.IsBusy()) 
     { 
      //Raise a "Completed" event to enable UI controls... 
     } 
    } 
} 

L'aspect de comptage est encapsulé dans BusyState qui est ensuite utilisé dans l'objet métier pour signaler les tâches de démarrage et d'arrêt. La levée des événements démarrés et terminés peut être accrochée pour implémenter l'activation et la désactivation des contrôles de l'interface utilisateur pour verrouiller l'utilisateur pendant que les opérations asynchrones sont en cours.

Il y a évidemment des charges de caveats ici pour manipuler des conditions d'erreur, etc.Donc juste un code de base ...