Compartir a través de


Esperando la respuesta asincrónica

Lo que hace el cliente mientras espera a recibir una notificación de una respuesta del servidor depende del mecanismo de notificación que seleccione.

Si el cliente usa un evento para la notificación, normalmente llamará a la función WaitForSingleObject o a la función WaitForSingleObjectEx . El cliente entra en un estado bloqueado cuando llama a cualquiera de estas funciones. Esto es eficaz porque el cliente no consume ciclos de ejecución de CPU mientras está bloqueado.

Cuando usa sondeo para esperar sus resultados, el programa cliente entra en un bucle que llama repetidamente a la función RpcAsyncGetCallStatus. Se trata de un método eficaz de esperar si el programa cliente realiza otro procesamiento en el bucle de sondeo. Por ejemplo, puede preparar los datos en pequeños fragmentos para una llamada de procedimiento remoto asincrónica posterior. Una vez finalizado cada fragmento, el cliente puede sondear la llamada de procedimiento remoto asincrónica pendiente para ver si se ha completado.

El programa cliente puede proporcionar una llamada a procedimiento asincrónico (APC), que es un tipo de función de devolución de llamada que la biblioteca en tiempo de ejecución RPC invocará cuando se complete la llamada de procedimiento remoto asincrónico. El programa cliente debe estar en un estado de espera alertable. Normalmente, esto significa que el cliente llama a una función de la API de Windows para colocarse en un estado bloqueado. Para obtener más información, vea Llamadas a procedimientos asincrónicos.

Nota

La notificación de finalización no se devolverá desde una rutina RPC asincrónica si se genera una excepción RPC durante una llamada asincrónica.

 

Si el programa cliente usa un puerto de finalización de E/S para recibir una notificación de finalización, debe llamar a la función GetQueuedCompletionStatus . Cuando lo hace, puede esperar indefinidamente una respuesta o continuar realizando otro procesamiento. Si realiza otro procesamiento mientras espera una respuesta, debe sondear el puerto de finalización con la función GetQueuedCompletionStatus . En este caso, normalmente debe establecer dwMilliseconds en cero. Esto hace que GetQueuedCompletionStatus se devuelva inmediatamente, incluso si la llamada asincrónica no se ha completado.

Los programas cliente también pueden recibir notificaciones de finalización a través de sus colas de mensajes de ventana. En esta situación, simplemente procesan el mensaje de finalización como harían con cualquier mensaje de Windows.

En una aplicación multiproceso, el cliente puede cancelar una llamada asincrónica solo después de que el subproceso que originó la llamada se haya devuelto correctamente desde la llamada. Esto garantiza que la llamada no se cancele de forma asincrónica por otro subproceso después de que se produjo un error en una llamada sincrónica. Como práctica estándar, una llamada asincrónica que produce un error sincrónicamente no debe cancelarse de forma asincrónica. La aplicación cliente debe observar este comportamiento si se pueden emitir y cancelar llamadas en diferentes subprocesos. Además, una vez cancelada la llamada, el código de cliente debe esperar a la notificación de finalización y completar la llamada. La función RpcAsyncCancelCall simplemente acelera la notificación de finalización; no es un sustituto de completar la llamada.

En el siguiente fragmento de código se muestra cómo un programa cliente puede usar un evento para esperar una respuesta asincrónica.

// This code fragment assumes that Async is a valid asynchronous
// RPC handle.
if (WaitForSingleObject(Async.u.hEvent, INFINITE) == WAIT_FAILED)
{
    RpcRaiseException(APP_ERROR);
}

Los programas cliente que usan un APC para recibir notificaciones de una respuesta asincrónica suelen colocarse en un estado bloqueado. El siguiente fragmento de código muestra esto.

if (SleepEx(INFINITE, TRUE) != WAIT_IO_COMPLETION)
{
    RpcRaiseException(APP_ERROR);
}

En este caso, el programa cliente deja de funcionar, sin ciclos de CPU, hasta que la biblioteca en tiempo de ejecución rpc llama al APC (no se muestra).

En el ejemplo siguiente se muestra un cliente que usa un puerto de finalización de E/S para esperar una respuesta asincrónica.

// 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);
}

En el ejemplo anterior, la llamada a GetQueuedCompletionStatus espera indefinidamente hasta que se complete la llamada de procedimiento remoto asincrónico.

Se produce un posible problema al escribir aplicaciones multiproceso. Si un subproceso invoca una llamada a procedimiento remoto y, a continuación, finaliza antes de recibir una notificación de que el envío se completó, la llamada a procedimiento remoto puede producir un error y el código auxiliar del cliente puede cerrar la conexión con el servidor. Por lo tanto, los subprocesos que llaman a un procedimiento remoto no deben finalizar antes de que la llamada se complete o cancele cuando el comportamiento no sea deseable.