Función WSAWaitForMultipleEvents (winsock2.h)

La función WSAWaitForMultipleEvents devuelve cuando uno o todos los objetos de evento especificados están en estado señalado, cuando expira el intervalo de tiempo de espera o cuando se ha ejecutado una rutina de finalización de E/S.

Sintaxis

DWORD WSAAPI WSAWaitForMultipleEvents(
  [in] DWORD          cEvents,
  [in] const WSAEVENT *lphEvents,
  [in] BOOL           fWaitAll,
  [in] DWORD          dwTimeout,
  [in] BOOL           fAlertable
);

Parámetros

[in] cEvents

Número de identificadores de objeto de evento en la matriz a la que apunta lphEvents. El número máximo de identificadores de objeto de evento es WSA_MAXIMUM_WAIT_EVENTS. Se deben especificar uno o varios eventos.

[in] lphEvents

Puntero a una matriz de identificadores de objeto de evento. La matriz puede contener identificadores de objetos de diferentes tipos. Puede que no contenga varias copias del mismo identificador si el parámetro fWaitAll está establecido en TRUE. Si se cierra uno de estos identificadores mientras la espera sigue pendiente, el comportamiento de WSAWaitForMultipleEvents no está definido.

Los identificadores deben tener el derecho de acceso SYNCHRONIZE . Para obtener más información, consulte Derechos de acceso estándar.

[in] fWaitAll

Valor que especifica el tipo de espera. Si es TRUE, la función devuelve cuando se señala el estado de todos los objetos de la matriz lphEvents . Si es FALSE, la función devuelve cuando se señala cualquiera de los objetos de evento. En este último caso, el valor devuelto menos WSA_WAIT_EVENT_0 indica el índice del objeto de evento cuyo estado hizo que la función devolva. Si se señalizó más de un objeto de evento durante la llamada, este es el índice de matriz para el objeto de evento señalado con el valor de índice más pequeño de todos los objetos de evento señalados.

[in] dwTimeout

El intervalo de tiempo de espera en milisegundos. WSAWaitForMultipleEvents devuelve si expira el intervalo de tiempo de espera, incluso si no se cumplen las condiciones especificadas por el parámetro fWaitAll . Si el parámetro dwTimeout es cero, WSAWaitForMultipleEvents comprueba el estado de los objetos de evento especificados y devuelve inmediatamente. Si dwTimeout es WSA_INFINITE, WSAWaitForMultipleEvents espera para siempre; es decir, el intervalo de tiempo de espera nunca expira.

[in] fAlertable

Valor que especifica si el subproceso se coloca en un estado de espera alertable para que el sistema pueda ejecutar rutinas de finalización de E/S. Si es TRUE, el subproceso se coloca en un estado de espera alertable y WSAWaitForMultipleEvents puede devolver cuando el sistema ejecuta una rutina de finalización de E/S. En este caso, se devuelve WSA_WAIT_IO_COMPLETION y aún no se señala el evento en el que se estaba esperando. La aplicación debe llamar de nuevo a la función WSAWaitForMultipleEvents . Si es FALSE, el subproceso no se coloca en un estado de espera alertable y no se ejecutan las rutinas de finalización de E/S.

Valor devuelto

Si la función WSAWaitForMultipleEvents se realiza correctamente, el valor devuelto tras el éxito es uno de los siguientes valores.

Valor devuelto Significado
WSA_WAIT_EVENT_0 a (WSA_WAIT_EVENT_0 + cEvents - 1)
Si el parámetro fWaitAll es TRUE, el valor devuelto indica que se señalizan todos los objetos de evento especificados.

Si el parámetro fWaitAll es FALSE, el valor devuelto menos WSA_WAIT_EVENT_0 indica el índice de matriz lphEvents del objeto de evento señalado que cumplió la espera. Si se señala más de un objeto de evento durante la llamada, el valor devuelto indica el índice de matriz lphEvents del objeto de evento señalado con el valor de índice más pequeño de todos los objetos de evento señalados.

WSA_WAIT_IO_COMPLETION
La espera finalizó con una o varias rutinas de finalización de E/S que se ejecutaron. Todavía no se señala el evento en el que se estaba esperando. La aplicación debe llamar de nuevo a la función WSAWaitForMultipleEvents . Este valor devuelto solo se puede devolver si el parámetro fAlertable es TRUE.
WSA_WAIT_TIMEOUT
No se cumplió el intervalo de tiempo de espera y las condiciones especificadas por el parámetro fWaitAll . No se ejecutaron rutinas de finalización de E/S.
 

Si se produce un error en la función WSAWaitForMultipleEvents , el valor devuelto es WSA_WAIT_FAILED. En la tabla siguiente se enumeran los valores que se pueden usar con WSAGetLastError para obtener información de error extendida.

Código de error Significado
WSANOTINITIALISED Debe producirse una llamada de WSAStartup correcta antes de usar esta función.
WSAENETDOWN Error en el subsistema de red.
WSAEINPROGRESS Una llamada de Bloqueo de Windows Sockets 1.1 está en curso o el proveedor de servicios sigue procesando una función de devolución de llamada.
WSA_NOT_ENOUGH_MEMORY No había suficiente memoria libre disponible para completar la operación.
WSA_INVALID_HANDLE Uno o varios de los valores de la matriz lphEvents no son un identificador de objeto de evento válido.
WSA_INVALID_PARAMETER El parámetro cEvents no contiene un recuento de identificadores válido.

Comentarios

La función WSAWaitForMultipleEvents determina si se han cumplido los criterios de espera. Si no se han cumplido los criterios, el subproceso que realiza la llamada entra en el estado de espera. No usa tiempo de procesador mientras espera a que se cumplan los criterios.

La función WSAWaitForMultipleEvents devuelve cuando cualquiera o todos los objetos especificados están en estado señalado o cuando transcurre el intervalo de tiempo de espera.

Cuando el parámetro bWaitAll es TRUE, la operación de espera solo se completa cuando los estados de todos los objetos se han establecido en señalizado. La función no modifica los estados de los objetos especificados hasta que los estados de todos los objetos se han establecido en señalizado.

Cuando el parámetro bWaitAll es FALSE, WSAWaitForMultipleEvents comprueba los identificadores de la matriz lphEvents en orden a partir del índice 0, hasta que se señala a uno de los objetos. Si se señalizan varios objetos, la función devuelve el índice del primer identificador de la matriz lphEvents cuyo objeto se señalizó.

Esta función también se usa para realizar una espera alertable estableciendo el parámetro fAlertable en TRUE. Esto permite que la función devuelva cuando el sistema ejecuta una rutina de finalización de E/S mediante el subproceso que realiza la llamada.

Un subproceso debe estar en un estado de espera alertable para que el sistema ejecute rutinas de finalización de E/S (llamadas de procedimiento asincrónico o API). Por lo tanto, si una aplicación llama a WSAWaitForMultipleEvents cuando hay operaciones asincrónicas pendientes que tienen rutinas de finalización de E/S y el parámetro fAlertable es FALSE, esas rutinas de finalización de E/S no se ejecutarán aunque se completen esas operaciones de E/S.

Si el parámetro fAlertable es TRUE y se completa una de las operaciones pendientes, se ejecuta APC y WSAWaitForMultipleEvents devolverá WSA_IO_COMPLETION. El evento pendiente aún no está señalado. La aplicación debe llamar de nuevo a la función WSAWaitForMultipleEvents .

Las aplicaciones que requieren un estado de espera alertable sin esperar a que se señale ningún objeto de evento deben usar la función SleepEx de Windows.

La implementación actual de WSAWaitForMultipleEvents llama a la función WaitForMultipleObjectsEx .

Nota Tenga cuidado al llamar a WSAWaitForMultipleEvents con código que crea ventanas directa o indirectamente. Si un subproceso crea ventanas, debe procesar mensajes. Las difusión de mensajes se envían a todas las ventanas del sistema. Un subproceso que usa WSAWaitForMultipleEvents sin límite de tiempo de espera (el parámetro dwTimeout establecido en WSA_INFINITE) puede hacer que el sistema se interbloquee.
 

Código de ejemplo

En el ejemplo de código siguiente se muestra cómo usar la función WSAWaitForMultipleEvents .
#ifndef UNICODE
#define UNICODE
#endif

#define WIN32_LEAN_AND_MEAN

#include <winsock2.h>
#include <Ws2tcpip.h>
#include <stdio.h>

// Link with ws2_32.lib
#pragma comment(lib, "Ws2_32.lib")

#define DATA_BUFSIZE 4096

int main()
{
    //-----------------------------------------
    // Declare and initialize variables
    WSADATA wsaData = { 0 };
    int iResult = 0;
    BOOL bResult = TRUE;

    WSABUF DataBuf;
    char buffer[DATA_BUFSIZE];

    DWORD EventTotal = 0;
    DWORD RecvBytes = 0;
    DWORD Flags = 0;
    DWORD BytesTransferred = 0;

    WSAEVENT EventArray[WSA_MAXIMUM_WAIT_EVENTS];
    WSAOVERLAPPED AcceptOverlapped;
    SOCKET ListenSocket = INVALID_SOCKET;
    SOCKET AcceptSocket = INVALID_SOCKET;

    DWORD Index;

    //-----------------------------------------
    // Initialize Winsock
    // Initialize Winsock
    iResult = WSAStartup(MAKEWORD(2, 2), &wsaData);
    if (iResult != 0) {
        wprintf(L"WSAStartup failed: %d\n", iResult);
        return 1;
    }
    //-----------------------------------------
    // Create a listening socket bound to a local
    // IP address and the port specified
    ListenSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
    if (ListenSocket == INVALID_SOCKET) {
        wprintf(L"socket failed with error = %d\n", WSAGetLastError());
        WSACleanup();
        return 1;
    }

    u_short port = 27015;
    char *ip;
    sockaddr_in service;
    service.sin_family = AF_INET;
    service.sin_port = htons(port);
    hostent *thisHost;

    thisHost = gethostbyname("");
    if (thisHost == NULL) {
        wprintf(L"gethostbyname failed with error = %d\n", WSAGetLastError());
        closesocket(ListenSocket);
        WSACleanup();
        return 1;
    }

    ip = inet_ntoa(*(struct in_addr *) *thisHost->h_addr_list);

    service.sin_addr.s_addr = inet_addr(ip);

    //-----------------------------------------
    // Bind the listening socket to the local IP address
    // and port number
    iResult = bind(ListenSocket, (SOCKADDR *) & service, sizeof (SOCKADDR));
    if (iResult != 0) {
        wprintf(L"bind failed with error = %d\n", WSAGetLastError());
        closesocket(ListenSocket);
        WSACleanup();
        return 1;
    }
    //-----------------------------------------
    // Set the socket to listen for incoming
    // connection requests
    iResult = listen(ListenSocket, 1);
    if (iResult != 0) {
        wprintf(L"listen failed with error = %d\n", WSAGetLastError());
        closesocket(ListenSocket);
        WSACleanup();
        return 1;
    }
    wprintf(L"Listening...\n");

    //-----------------------------------------
    // Accept and incoming connection request
    AcceptSocket = accept(ListenSocket, NULL, NULL);
    if (AcceptSocket == INVALID_SOCKET) {
        wprintf(L"accept failed with error = %d\n", WSAGetLastError());
        closesocket(ListenSocket);
        WSACleanup();
        return 1;
    }
    wprintf(L"Client Accepted...\n");

    //-----------------------------------------
    // Create an event handle and setup an overlapped structure.
    EventArray[EventTotal] = WSACreateEvent();
    if (EventArray[EventTotal] == WSA_INVALID_EVENT) {
        wprintf(L"WSACreateEvent failed with error = %d\n", WSAGetLastError());
        closesocket(AcceptSocket);
        closesocket(ListenSocket);
        WSACleanup();
        return 1;
    }

    ZeroMemory(&AcceptOverlapped, sizeof (WSAOVERLAPPED));
    AcceptOverlapped.hEvent = EventArray[EventTotal];

    DataBuf.len = DATA_BUFSIZE;
    DataBuf.buf = buffer;

    EventTotal++;

    //-----------------------------------------
    // Call WSARecv to receive data into DataBuf on 
    // the accepted socket in overlapped I/O mode
    if (WSARecv(AcceptSocket, &DataBuf, 1, &RecvBytes, &Flags, &AcceptOverlapped, NULL) ==
        SOCKET_ERROR) {
        iResult = WSAGetLastError();
        if (iResult != WSA_IO_PENDING)
            wprintf(L"WSARecv failed with error = %d\n", iResult);
    }
    //-----------------------------------------
    // Process overlapped receives on the socket
    while (1) {

        //-----------------------------------------
        // Wait for the overlapped I/O call to complete
        Index = WSAWaitForMultipleEvents(EventTotal, EventArray, FALSE, WSA_INFINITE, FALSE);

        //-----------------------------------------
        // Reset the signaled event
        bResult = WSAResetEvent(EventArray[Index - WSA_WAIT_EVENT_0]);
        if (bResult == FALSE) {
            wprintf(L"WSAResetEvent failed with error = %d\n", WSAGetLastError());
        }
        //-----------------------------------------
        // Determine the status of the overlapped event
        bResult =
            WSAGetOverlappedResult(AcceptSocket, &AcceptOverlapped, &BytesTransferred, FALSE,
                                   &Flags);
        if (bResult == FALSE) {
            wprintf(L"WSAGetOverlappedResult failed with error = %d\n", WSAGetLastError());
        }
        //-----------------------------------------
        // If the connection has been closed, close the accepted socket
        if (BytesTransferred == 0) {
            wprintf(L"Closing accept Socket %d\n", AcceptSocket);
            closesocket(ListenSocket);
            closesocket(AcceptSocket);
            WSACloseEvent(EventArray[Index - WSA_WAIT_EVENT_0]);
            WSACleanup();
            return 1;
        }
        //-----------------------------------------
        // If data has been received, echo the received data
        // from DataBuf back to the client
        iResult =
            WSASend(AcceptSocket, &DataBuf, 1, &RecvBytes, Flags, &AcceptOverlapped, NULL);
        if (iResult != 0) {
            wprintf(L"WSASend failed with error = %d\n", WSAGetLastError());
        }
        //-----------------------------------------         
        // Reset the changed flags and overlapped structure
        Flags = 0;
        ZeroMemory(&AcceptOverlapped, sizeof (WSAOVERLAPPED));

        AcceptOverlapped.hEvent = EventArray[Index - WSA_WAIT_EVENT_0];

        //-----------------------------------------
        // Reset the data buffer
        DataBuf.len = DATA_BUFSIZE;
        DataBuf.buf = buffer;
    }

    closesocket(ListenSocket);
    closesocket(AcceptSocket);
    WSACleanup();

    return 0;
}


Windows Phone 8: esta función es compatible con las aplicaciones de Windows Phone Store en Windows Phone 8 y versiones posteriores.

Windows 8.1 y Windows Server 2012 R2: esta función es compatible con las aplicaciones de la Tienda Windows en Windows 8.1, Windows Server 2012 R2 y versiones posteriores.

Requisitos

   
Cliente mínimo compatible Windows 8.1, Windows Vista [aplicaciones de escritorio | Aplicaciones para UWP]
Servidor mínimo compatible Windows Server 2003 [aplicaciones de escritorio | aplicaciones para UWP]
Plataforma de destino Windows
Encabezado winsock2.h
Library Ws2_32.lib
Archivo DLL Ws2_32.dll

Consulte también

Derechos de acceso estándar

WSACloseEvent

WSACreateEvent

WaitForMultipleObjectsEx

Funciones winsock

Referencia de Winsock