Attente de la réponse asynchrone
Ce que fait le client pendant qu’il attend d’être averti d’une réponse du serveur dépend du mécanisme de notification qu’il sélectionne.
Si le client utilise un événement pour la notification, il appelle généralement la fonction WaitForSingleObject ou la fonction WaitForSingleObjectEx . Le client passe à l’état bloqué lorsqu’il appelle l’une de ces fonctions. Cela est efficace, car le client ne consomme pas de cycles d’exécution du processeur pendant qu’il est bloqué.
Quand il utilise l’interrogation pour attendre ses résultats, le programme client entre dans une boucle qui appelle à plusieurs reprises la fonction RpcAsyncGetCallStatus. Il s’agit d’une méthode efficace d’attente si votre programme client effectue d’autres traitements dans la boucle d’interrogation. Par instance, il peut préparer des données en petits blocs pour un appel de procédure distante asynchrone ultérieur. Une fois chaque bloc terminé, votre client peut interroger l’appel de procédure distante asynchrone en attente pour voir s’il est terminé.
Votre programme client peut fournir un appel de procédure asynchrone (APC), qui est un type de fonction de rappel que la bibliothèque d’exécution RPC appellera une fois l’appel de procédure distante asynchrone terminé. Votre programme client doit être dans un état d’attente pouvant être alerté. Cela signifie généralement que le client appelle une fonction d’API Windows pour se placer dans un état bloqué. Pour plus d’informations, consultez Appels de procédure asynchrone.
Notes
La notification d’achèvement ne sera pas retournée par une routine RPC asynchrone si une exception RPC est déclenchée pendant un appel asynchrone.
Si votre programme client utilise un port d’achèvement d’E/S pour recevoir une notification d’achèvement, il doit appeler la fonction GetQueuedCompletionStatus . Dans ce cas, il peut attendre indéfiniment une réponse ou continuer à effectuer d’autres traitements. S’il effectue d’autres traitements pendant qu’il attend une réponse, il doit interroger le port d’achèvement avec la fonction GetQueuedCompletionStatus . Dans ce cas, il doit généralement définir la valeur dwMillisecondes sur zéro. Cela entraîne le retour immédiat de GetQueuedCompletionStatus , même si l’appel asynchrone n’est pas terminé.
Les programmes clients peuvent également recevoir une notification d’achèvement via leurs files d’attente de messages de fenêtre. Dans ce cas, ils traitent simplement le message d’achèvement comme ils le feraient pour n’importe quel message Windows.
Dans une application multithread, un appel asynchrone peut être annulé par le client uniquement une fois que le thread à l’origine de l’appel a été retourné à partir de l’appel. Cela garantit que l’appel n’est pas annulé de façon asynchrone par un autre thread après l’échec d’un appel synchrone. En pratique standard, un appel asynchrone qui échoue de façon synchrone ne doit pas être annulé de façon asynchrone. L’application cliente doit observer ce comportement si des appels peuvent être émis et annulés sur différents threads. En outre, une fois l’appel annulé, le code client doit attendre la notification d’achèvement et terminer l’appel. La fonction RpcAsyncCancelCall précipite simplement la notification d’achèvement ; elle ne remplace pas la fin de l’appel.
Le fragment de code suivant illustre comment un programme client peut utiliser un événement pour attendre une réponse asynchrone.
// This code fragment assumes that Async is a valid asynchronous
// RPC handle.
if (WaitForSingleObject(Async.u.hEvent, INFINITE) == WAIT_FAILED)
{
RpcRaiseException(APP_ERROR);
}
Les programmes clients qui utilisent un APC pour recevoir la notification d’une réponse asynchrone se mettent généralement dans un état bloqué. Le fragment de code suivant le montre.
if (SleepEx(INFINITE, TRUE) != WAIT_IO_COMPLETION)
{
RpcRaiseException(APP_ERROR);
}
Dans ce cas, le programme client est en veille, ne consommant aucun cycle d’uc, jusqu’à ce que la bibliothèque d’exécution RPC appelle l’APC (non affiché).
L’exemple suivant illustre un client qui utilise un port d’achèvement des E/S pour attendre une réponse asynchrone.
// This code fragment assumes that Async is a valid asynchronous
// RPC handle.
if (!GetQueuedCompletionStatus(
Async.u.IOC.hIOPort,
&Async.u.IOC.dwNumberOfBytesTransferred,
&Async.u.IOC.dwCompletionKey,
&Async.u.IOC.lpOverlapped,
INFINITE))
{
RpcRaiseException(APP_ERROR);
}
Dans l’exemple précédent, l’appel à GetQueuedCompletionStatus attend indéfiniment jusqu’à la fin de l’appel de procédure distante asynchrone.
Un piège potentiel se produit lors de l’écriture d’applications multithread. Si un thread appelle un appel de procédure distante, puis se termine avant de recevoir une notification indiquant que l’envoi est terminé, l’appel de procédure distante peut échouer et le stub client peut fermer la connexion au serveur. Par conséquent, les threads qui appellent une procédure distante ne doivent pas se terminer avant la fin de l’appel ou l’annuler lorsque le comportement n’est pas souhaitable.