2010-01-21 11 views
2

J'essaie d'adapter un programme existant (écrit en interne) pour utiliser une bibliothèque différente de celle utilisée à l'origine. J'ai extrait la majeure partie du code spécifique à la bibliothèque (semble être la partie la plus facile). Le problème est que l'ancienne bibliothèque exécuterait un appel en utilisant une méthode de blocage, et notre programme interne attend une méthode de blocage, mais la nouvelle bibliothèque utilise une méthode asynchrone.Meilleure pratique: bloquer l'exécution en attendant une méthode asynchrone

Je me demandais quelle serait la meilleure pratique pour attendre l'achèvement de l'opération asynchrone. Ma première pensée a été d'avoir un drapeau booléen appelé terminé, et de tourner dans une boucle while jusqu'à la fin == true.

Je tiens à souligner qu'il s'agit d'une preuve de concept rapide que j'essaie de mettre en place pour mon intervenant, et si les intervenants approuvent le projet, je vais réécrire la partie incriminée de notre programme. Mais pour le moment, je dois juste attendre que le bloc de la fonction appelant la méthode async jusqu'à ce que l'appel asynchrone est terminé

Répondre

2

Au lieu d'un drapeau, je pense que vous voudriez utiliser quelque chose comme un mutex. Pour ce faire, cette bibliothèque doit avoir un événement à vous notifier une fois votre appel asynchrone terminé. Il ressemblerait à ceci:

  1. Créez votre mutex
  2. Dans votre async méthode complète, ajouter « myMutex.Release(); »
  3. Dans votre principale méthode, après avoir appelé la méthode async, ajouter dans « myMutex.WaitOne(); ». cela bloque le fil jusqu'à ce que votre appel asynchrone est terminé

il a été un moment que je l'ai utilisé ce genre de choses, mais je suis sûr que comment il se doit.

modifier: Oops, je pense que je pensais à un semaphore, non mutex:

private static Semaphore mySemaphore = new Semaphore(0, 1); 

    static void Main(string[] args) 
    { 
     Console.WriteLine("Waiting on async call"); 
     (new Thread(ASyncCallCompleted)).Start(); 
     mySemaphore.WaitOne(); 
     Console.WriteLine("Waiting Completed"); 
    } 

    private static void ASyncCallCompleted() 
    { 
     Thread.Sleep(5000); 
     mySemaphore.Release(); 
    } 

modifier # 2: par la suggestion de Thorarin; il semble que cette classe a été conçu pour gérer des situations comme celle-ci en .Net:

private static AutoResetEvent mySync = new AutoResetEvent(false); 

    static void Main(string[] args) 
    { 
     Console.WriteLine("Waiting on async call"); 
     (new Thread(ASyncCallCompleted)).Start(); 
     mySync.WaitOne(); 
     Console.WriteLine("Waiting Completed"); 
     Console.Read(); 
    } 

    private static void ASyncCallCompleted() 
    { 
     Thread.Sleep(5000); 
     mySync.Set(); 
    } 
+0

cela fonctionnerait à moins que la méthode async soit rapide et que la release soit appelée avant waitone ... –

+0

J'ai légèrement changé la réponse. Je pense que si le sémaphore est libéré avant l'appel de la méthode "WaitOne", il ne bloquera pas – John

+0

'AutoResetEvent' aurait plus de sens que' Semaphore'. En outre, cet exemple devra être modifié si vous souhaitez prendre en compte plusieurs appels simultanés dans un environnement multithread. – Thorarin

2

Pass Loquet un compte à rebours à la méthode async, et attendez le loquet. Lorsque la méthode async est terminée, elle vous avertira sur le verrou du compte à rebours et l'exécution pourra continuer. Un moniteur peut également être utilisé, mais n'est pas sûr dans le cas malheureux où la méthode async se termine avant que vous puissiez appeler wait, et vous manquez donc la notification.

Oh, et dans le monde .NET, un verrou à rebours est appelé CountdownEvent: CountdownEvent Class

+0

'AutoResetEvent' fera aussi bien, car rien ne doit être compté. Et puisque 'CountdownEvent' est .NET 4.0 seulement aussi bien ... Je suis content qu'ils l'aient ajouté cependant. – Thorarin

1

Cela devrait fonctionner pour au plus un appel simultané à BlockingCall. Dans le cas contraire, vous aurez besoin d'instances AutoResetEvent distinctes pour déterminer quel appel est terminé. Anyway:

delegate void Callback(); 

class BlockAsync 
{ 
    AutoResetEvent _waitHandle = new AutoResetEvent(false); 

    public void BlockingCall() 
    { 
     AsyncCall(AsyncCallCompleted); 
     _waitHandle.WaitOne(); 
    } 

    void AsyncCall(Callback callback) 
    { 
     // Example is not actually asynchronous, to demonstrate the solution 
     // is free of race conditions. 
     callback(); 
    } 

    void AsyncCallCompleted() 
    { 
     _waitHandle.Set(); 
    } 
} 
Questions connexes