WSAWaitForMultipleEvents 関数 (winsock2.h)

WSAWaitForMultipleEvents 関数は、指定されたイベント オブジェクトの 1 つ以上がシグナル状態にある場合、タイムアウト間隔が切れたとき、または I/O 完了ルーチンが実行されたときにを返します。

構文

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

パラメーター

[in] cEvents

lphEvents が指す配列内のイベント オブジェクト ハンドルの数。 イベント オブジェクト ハンドルの最大数は WSA_MAXIMUM_WAIT_EVENTS。 1 つ以上のイベントを指定する必要があります。

[in] lphEvents

イベント オブジェクト ハンドルの配列へのポインター。 配列には、さまざまな型のオブジェクトのハンドルを含めることができます。 fWaitAll パラメーターが TRUE に設定されている場合、同じハンドルの複数のコピーが含まれていない可能性があります。 待機がまだ保留中の間にこれらのハンドルのいずれかが閉じている場合、 WSAWaitForMultipleEvents の動作は未定義です。

ハンドルには SYNCHRONIZE アクセス権が必要です。 詳細については、「 Standard Access Rights」を参照してください。

[in] fWaitAll

待機の種類を示す 値。 TRUE の場合、関数は、lphEvents 配列内のすべてのオブジェクトの状態がシグナル通知されると を返します。 FALSE の場合、いずれかのイベント オブジェクトがシグナル通知されると、関数は を返します。 後者の場合、戻り値 から WSA_WAIT_EVENT_0 を引いた値は、関数が戻る原因となった状態のイベント オブジェクトのインデックスを示します。 呼び出し中に複数のイベント オブジェクトがシグナル化された場合、これはシグナルイベントオブジェクトへの配列インデックスであり、すべてのシグナルイベントオブジェクトの最小インデックス値を持ちます。

[in] dwTimeout

タイムアウト間隔 (ミリ秒単位)。 wsAWaitForMultipleEvents は、 fWaitAll パラメーターで指定された条件が満たされない場合でも、タイムアウト間隔が切れた場合に を返します。 dwTimeout パラメーターが 0 の場合、WSAWaitForMultipleEvents は指定されたイベント オブジェクトの状態をテストし、すぐに返します。 dwTimeoutWSA_INFINITE場合、WSAWaitForMultipleEvents は永久に待機します。つまり、タイムアウト間隔は期限切れになりません。

[in] fAlertable

システムが I/O 完了ルーチンを実行できるように、スレッドを警告可能な待機状態にするかどうかを示す 値。 TRUE の場合、スレッドは警告可能な待機状態になり、システムが I/O 完了ルーチンを実行するときに WSAWaitForMultipleEvents が返される可能性があります。 この場合、 WSA_WAIT_IO_COMPLETION が返され、待機中のイベントはまだ通知されません。 アプリケーションは WSAWaitForMultipleEvents 関数を再度呼び出す必要があります。 FALSE の場合、スレッドは警告可能な待機状態に配置されず、I/O 完了ルーチンは実行されません。

戻り値

WSAWaitForMultipleEvents 関数が成功した場合、成功した場合の戻り値は次のいずれかの値になります。

戻り値 説明
にWSA_WAIT_EVENT_0 (WSA_WAIT_EVENT_0 + cEvents - 1)
fWaitAll パラメーターが TRUE の場合、戻り値は、指定されたすべてのイベント オブジェクトがシグナル通知されることを示します。

fWaitAll パラメーターが FALSE の場合、戻り値から WSA_WAIT_EVENT_0 を引いた値は、待機を満たすシグナルイベント オブジェクトの lphEvents 配列インデックスを示します。 呼び出し中に複数のイベント オブジェクトがシグナル化された場合、戻り値は、シグナルイベント オブジェクトの lphEvents 配列インデックスと、すべてのシグナルイベント オブジェクトの最小インデックス値を示します。

WSA_WAIT_IO_COMPLETION
待機は、実行された 1 つ以上の I/O 完了ルーチンによって終了されました。 待機中のイベントはまだ通知されていません。 アプリケーションは WSAWaitForMultipleEvents 関数を再度呼び出す必要があります。 この戻り値は、 fAlertable パラメーターが TRUE の場合にのみ返すことができます。
WSA_WAIT_TIMEOUT
タイムアウト間隔が経過し、 fWaitAll パラメーターで指定された条件が満たされませんでした。 I/O 完了ルーチンは実行されませんでした。
 

WSAWaitForMultipleEvents 関数が失敗した場合、戻り値はWSA_WAIT_FAILED。 次の表は、 WSAGetLastError で拡張エラー情報を取得するために使用できる値の一覧です。

エラー コード 意味
WSANOTINITIALISED この関数を使用する前に 、WSAStartup 呼び出しが正常に行われる必要があります。
WSAENETDOWN ネットワーク サブシステムが失敗しました。
WSAEINPROGRESS ブロックしている Windows ソケット 1.1 呼び出しが進行中であるか、サービス プロバイダーがコールバック関数を処理しています。
WSA_NOT_ENOUGH_MEMORY 操作を完了するのに十分な空きメモリが不足していました。
WSA_INVALID_HANDLE lphEvents 配列内の 1 つ以上の値が有効なイベント オブジェクト ハンドルではありません。
WSA_INVALID_PARAMETER cEvents パラメーターに有効なハンドル数が含まれていません。

解説

WSAWaitForMultipleEvents 関数は、待機条件が満たされているかどうかを判断します。 条件が満たされていない場合、呼び出し元のスレッドは待機状態になります。 条件が満たされるのを待っている間、プロセッサ時間は使用されません。

WSAWaitForMultipleEvents 関数は、指定されたオブジェクトの 1 つ以上がシグナル状態にある場合、またはタイムアウト間隔が経過したときにを返します。

bWaitAll パラメーターが TRUE の場合、待機操作は、すべてのオブジェクトの状態が signaled に設定されている場合にのみ完了します。 関数は、すべてのオブジェクトの状態が signaled に設定されるまで、指定されたオブジェクトの状態を変更しません。

bWaitAll パラメーターが FALSE の場合、WSAWaitForMultipleEvents は、オブジェクトの 1 つがシグナル通知されるまで、インデックス 0 で始まる順序で lphEvents 配列内のハンドルをチェックします。 複数のオブジェクトがシグナル化された場合、関数はオブジェクトがシグナル通知された lphEvents 配列内の最初のハンドルのインデックスを返します。

この関数は、 fAlertable パラメーターを TRUE に設定して、アラート可能な待機を実行するためにも使用されます。 これにより、システムが呼び出し元のスレッドによって I/O 完了ルーチンを実行したときに、関数が を返します。

システムが I/O 完了ルーチン (非同期プロシージャ呼び出しまたは APC) を実行するには、スレッドが警告可能な待機状態である必要があります。 そのため、I/O 完了ルーチンを持つ保留中の非同期操作があり、fAlertable パラメーターが FALSE の場合、アプリケーションが WSAWaitForMultipleEvents を呼び出す場合、それらの I/O 完了ルーチンは、それらの I/O 操作が完了しても実行されません。

fAlertable パラメーターが TRUE で、保留中の操作のいずれかが完了した場合、APC が実行され、WSAWaitForMultipleEventsWSA_IO_COMPLETIONを返します。 保留中のイベントはまだ通知されていません。 アプリケーションは WSAWaitForMultipleEvents 関数を再度呼び出す必要があります。

通知されるイベント オブジェクトを待機せずにアラート可能な待機状態を必要とするアプリケーションでは、Windows SleepEx 関数を使用する必要があります。

WSAWaitForMultipleEvents の現在の実装では、WaitForMultipleObjectsEx 関数が呼び出されます。

メモ 直接または間接的にウィンドウを作成するコードを使用して WSAWaitForMultipleEvents を呼び出す場合は注意が必要です。 スレッドがウィンドウを作成する場合は、メッセージを処理する必要があります。 メッセージ ブロードキャストは、システム内のすべてのウィンドウに送信されます。 タイムアウト制限のない WSAWaitForMultipleEvents を使用するスレッド ( dwTimeout パラメーターを WSA_INFINITE に設定) すると、システムがデッドロックになる可能性があります。
 

コード例

次のコード例は、 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: この関数は、Windows Phone 8 以降のWindows Phone ストア アプリでサポートされています。

Windows 8.1Windows Server 2012 R2: この関数は、Windows 8.1、Windows Server 2012 R2 以降の Windows ストア アプリでサポートされています。

要件

   
サポートされている最小のクライアント Windows 8.1、 Windows Vista [デスクトップ アプリ |UWP アプリ]
サポートされている最小のサーバー Windows Server 2003 [デスクトップ アプリのみ | UWP アプリ]
対象プラットフォーム Windows
ヘッダー winsock2.h
Library Ws2_32.lib
[DLL] Ws2_32.dll

関連項目

Standard Access Rights

WSACloseEvent

WSACreateEvent

WaitForMultipleObjectsEx

Winsock 関数

Winsock リファレンス