2010-08-01 8 views
0

j'ai une classe qui expose deux méthodes:C# Synchronisez WAIT/méthodes du sondage

-GetObject

Obtient un seul objet ou renvoie null s'il n'y en a pas.

- WaitForObject

Obtient un seul objet, ou attend jusqu'à ce que leur est un.

Un exemple d'implémentation:

class MyClass 
    { 
        MyStack stack; 
        public object GetObject() 
        { 
            return stack.Pop(); 
        } 
        public object WaitForObject() 
        { 
            object returnValue; 
            while (returnValue == null) 
                returnValue = stack.Pop() 
            return returnValue 
        } 
    } 

En supposant que MyStack est thread-safe, comment puis-je faire en toute sécurité fil MyClass? C'est à dire.

-GetObject ne devrait jamais bloquer - Thread faire WaitForObject devrait obtenir de nouveaux objets ajoutés à la pile au lieu de GetObject.

Pour les points bonus, comment les utilisateurs qui ajoutent des objets à la pile peuvent-ils informer les auditeurs qu'un nouvel objet est disponible? (suppression de la nécessité d'interrogation)

+0

S'il vous plaît formater votre code;) –

+0

@ Martin - Désolé, je l'ai écrit sur mon téléphone. – Justin

+0

Si vous êtes sur .NET 4, vous pouvez simplement utiliser 'BlockingCollection ', en passant un 'ConcurrentStack ' dans son constructeur. –

Répondre

1

Si MyStack est garanti pour être thread-safe, MyClass est également thread-safe. Dans les deux méthodes, vous utilisez uniquement des variables locales, donc les méthodes sont réentrantes.

Actuellement, les utilisateurs ne peuvent pas ajouter d'objets à la pile car le champ stack n'est pas visible en dehors de la classe. De plus, je ne vois pas dans votre code comment les auditeurs s'abonnent à des événements pour être avertis si un objet est ajouté. Vous pouvez donc avoir une méthode permettant d'ajouter des éléments à la pile et un événement qui sera déclenché dans ce cas.

0

L'interrogation implique généralement une certaine forme de sommeil - la boucle dans votre exemple serait une boucle serrée qui étranglerait la tête tout le temps. Ajoutez un appel Thread.Sleep(100) ou une autre valeur sensible pour effectuer un sondage dans le temps. L'autre façon d'attendre serait d'enregistrer un rappel, ou que la pile expose une méthode de blocage Pop, de toute façon, celles-ci seraient implémentées dans la classe Stack dans votre exemple.

Bonus de réponse: Votre classe aurait besoin d'exposer un événement, quand ils ajoutent un objet à la pile, il déclencherait cet événement.

class MyClass 
    { 
     MyStack stack; 
     public object GetObject() 
     { 
      return stack.Pop(); 
     } 
     public object WaitForObject() 
     { 
      object returnValue; 
      while (returnValue == null) 
       returnValue = stack.Pop() 
      return returnValue 
     } 
     public void AddObject(object o) 
     { 
      stack.Push(o); 
      OnObjectAdded(); 
     } 
     public event EventHandler ObjectAdded; 

     private void OnObjectAdded() 
     { 
      if (ObjectAdded != null) 
       ObjectAdded(this, EventArgs.Empty); 
     } 
    } 
+0

Occupé en attente avec Thread.Sleep est une mauvaise idée. Utilisez une minuterie ou un rappel que vous mentionnez. –

+0

Ce rappel devrait être implémenté sur la collection sous-jacente (c'est-à-dire, sa pile). En supposant un System.Threading.Timer ou un système.Minuterie, puis la coche de la minuterie ne serait pas garanti pour fonctionner sur le même fil. Ce n'est pas nécessairement un problème, mais ce n'est peut-être pas souhaitable. –

+0

@Mikael Je suis généralement d'accord, mais pour garder l'interrogation sur le même fil, il n'y a malheureusement pas beaucoup d'options. –

1

Je pense que vous pouvez tout réaliser avec la fonctionnalité Moniteur. juste un croquis

class MyClass 
{ 
    private Stack<object> stack = new Stack<object>(); 
    public object GetObject() 
    { 
     lock(stack) 
     { 
      return stack.Count != 0 ? stack.Pop() : null; 
     } 
    } 
    public object WaitForObject() 
    { 
     lock (stack) 
     { 
      if (stack.Count == 0) 
      { 
       // wait until PutObject is called 
       Monitor.Wait(stack); 
      } 

      return stack.Pop(); 
     } 
    } 

    public void PutObject(object obj) 
    { 
     lock (stack) 
     { 
      stack.Push(obj); 
      // notify one thread blocked by WaitForObject call 
      Monitor.Pulse(obj); 
     } 
    } 
}