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


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

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

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

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

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

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

  • БТР. Клиент может указать асинхронный вызов процедуры (APC) , который вызывается по завершении вызова. Прототип функции APC см. в RPCNOTIFICATION_ROUTINE. APC вызывается с параметром Event, заданным для RpcCallComplete. Чтобы API-интерфейсы были отправлены, поток клиента должен находиться в состоянии ожидания, допускающего оповещение.

    Если поле hThread в асинхронном дескрипторе имеет значение 0, АПК помещаются в очередь в потоке, который сделал асинхронный вызов. Если это значение не равно нулю, асинхронные вызовы процедур (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 возникает во время асинхронного вызова.