Поделиться через


Выполнение асинхронного вызова

Прежде чем выполнять асинхронный удаленный вызов, клиент должен инициализировать асинхронный дескриптор. Клиентские и серверные программы используют указатели на структуру RPC_ASYNC_STATE для асинхронных дескрипторов.

Каждый выдающийся вызов должен иметь собственный уникальный асинхронный дескриптор. Клиент создает дескриптор и передает его функции RpcAsyncInitializeHandle . Для правильного завершения вызова клиент должен убедиться, что память дескриптора не освобождается, пока не получит асинхронный ответ сервера. Кроме того, перед выполнением другого вызова существующего асинхронного дескриптора клиент должен повторно инициализировать дескриптор. В этом случае заглушка клиента может вызвать исключение во время вызова. Клиент также должен убедиться, что буферы, которые он предоставляет для параметров [out] и [in, out] для асинхронной удаленной процедуры, остаются выделенными до получения ответа от сервера.

При вызове асинхронной удаленной процедуры клиент должен выбрать метод, который библиотека времени выполнения RPC будет использовать для уведомления о завершении вызова. Клиент может получить это уведомление одним из следующих способов:

  • Событие. Клиент может указать событие, которое будет запущено после завершения вызова. Дополнительные сведения см. в разделе Объекты событий.

  • опрос; Клиент может многократно вызывать RpcAsyncGetCallStatus. Если возвращаемое значение отличается от RPC_S_ASYNC_CALL_PENDING, вызов завершается. Этот метод использует больше времени ЦП, чем другие методы, описанные здесь.

  • APC. Клиент может указать асинхронный вызов процедуры (APC ), который вызывается после завершения вызова. Прототип функции APC см. в разделе RPCNOTIFICATION_ROUTINE. APC вызывается с параметром Event, равным RpcCallComplete. Для отправки APC поток клиента должен находиться в состоянии ожидания с поддержкой оповещений.

    Если для поля hThread в асинхронном дескрипторове задано значение 0, то APC помещаются в очередь в потоке, который совершил асинхронный вызов. Если это ненулевое значение, то APC помещаются в очередь в потоке, указанном в параметре m.

  • МОК. Порт завершения ввода-вывода получает уведомление с параметрами, указанными в асинхронном дескрипторове. Дополнительные сведения см. в разделе CreateIoCompletionPort.

  • Дескриптор Windows. Сообщение будет отправлено в указанный дескриптор окна (HWND).

В следующем фрагменте кода показаны основные шаги, необходимые для инициализации асинхронного дескриптора и его использования для асинхронного вызова удаленной процедуры.

RPC_ASYNC_STATE Async;
RPC_STATUS status;
 
// Initialize the handle.
status = RpcAsyncInitializeHandle(&Async, sizeof(RPC_ASYNC_STATE));
if (status)
{
    // Code to handle the error goes here.
}
 
Async.UserInfo = NULL;
Async.NotificationType = RpcNotificationTypeEvent;
 
Async.u.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if (Async.u.hEvent == 0)
{
    // Code to handle the error goes here.
}
// Call an asynchronous RPC routine here
RpcTryExcept
{
    printf("\nCalling the remote procedure 'AsyncFunc'\n");
    AsyncFunc(&Async, AsyncRPC_ClientIfHandle, nAsychDelay);
}
RpcExcept(1)
{
    ulCode = RpcExceptionCode();
    printf("AsyncFunc: Run time reported exception 0x%lx = %ld\n", 
            ulCode, ulCode);
}
RpcEndExcept
 
// Call a synchronous routine while
// the asynchronous procedure is still running
RpcTryExcept
{
    printf("\nCalling the remote procedure 'NonAsyncFunc'\n");
    NonAsyncFunc(AsyncRPC_ClientIfHandle, pszMessage);
    fprintf(stderr, 
            "While 'AsyncFunc' is running asynchronously,\n"
            "we still can send message to the server in the mean "
            "time.\n\n");
}
RpcExcept(1)
{
    ulCode = RpcExceptionCode();
    printf("NonAsyncFunc: Run time reported exception 0x%lx = %ld\n", 
            ulCode, ulCode);
}
RpcEndExcept

Как показано в этом примере, клиентская программа может выполнять синхронные удаленные вызовы процедур, пока асинхронный вызов процедуры все еще находится в состоянии ожидания. Этот клиент создает объект события для библиотеки времени выполнения RPC, который будет использоваться для уведомления о завершении асинхронного вызова.

Примечание

Уведомление о завершении не возвращается из асинхронной подпрограммы RPC, если во время асинхронного вызова возникает исключение RPC.