WaitForMultipleObjects和WSAWaitForMultipleEvents能否混用
如题,感觉两个函数都是对句柄数组进行检测,只是WSAWaitForMultipleEvents仅针对事件句柄(任然是handle),WaitForMultipleObjects针对的句柄种类多。如果在句柄类型都为事件句柄的情况下,两个函数能否混用?如果能混用,功能上有什么区别?
// 简单的WSAEventSelect模型 // ////////////////////////////////////////////////// // WSAEventSelect文件 #include <stdio.h> #include <WinSock2.h> #pragma comment (lib,"WS2_32") int main() { // 事件句柄和套节字句柄表 WSAEVENT eventArray[WSA_MAXIMUM_WAIT_EVENTS];//64 SOCKET sockArray[WSA_MAXIMUM_WAIT_EVENTS]; int nEventTotal = 0; USHORT nPort = 4567; // 此服务器监听的端口号 // 创建监听套节字 SOCKET sListen =socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); sockaddr_in sin; sin.sin_family = AF_INET; sin.sin_port = htons(nPort); sin.sin_addr.S_un.S_addr = INADDR_ANY; if(bind(sListen, (sockaddr*)&sin, sizeof(sin)) == SOCKET_ERROR) { printf(" Failed bind() \n"); return -1; } listen(sListen, 5); // 创建事件对象,并关联到新的套节字 WSAEVENT event = WSACreateEvent(); WSAEventSelect(sListen, event, FD_ACCEPT|FD_CLOSE); // 添加到表中 eventArray[nEventTotal] = event; sockArray[nEventTotal] = sListen; nEventTotal++; // 处理网络事件 while(TRUE) { // 在所有事件对象上等待 int nIndex = WSAWaitForMultipleEvents(nEventTotal, eventArray, FALSE, WSA_INFINITE, FALSE); // 对每个事件调用WSAWaitForMultipleEvents函数,以便确定它的状态 nIndex = nIndex - WSA_WAIT_EVENT_0; for(int i=nIndex; i<nEventTotal; i++) { nIndex = WSAWaitForMultipleEvents(1, &eventArray[i], TRUE, 1000, FALSE); if(nIndex == WSA_WAIT_FAILED || nIndex == WSA_WAIT_TIMEOUT) { continue; } else { // 获取到来的通知消息,WSAEnumNetworkEvents函数会自动重置受信事件 WSANETWORKEVENTS event; WSAEnumNetworkEvents(sockArray[i], eventArray[i], &event); if(event.lNetworkEvents & FD_ACCEPT) // 处理FD_ACCEPT通知消息 { if(event.iErrorCode[FD_ACCEPT_BIT] == 0) { if(nEventTotal > WSA_MAXIMUM_WAIT_EVENTS) { printf(" Too many connections! \n"); continue; } SOCKET sNew = accept(sockArray[i], NULL, NULL); WSAEVENT event = WSACreateEvent(); WSAEventSelect(sNew, event, FD_READ|FD_CLOSE|FD_WRITE); // 添加到表中 eventArray[nEventTotal] = event; sockArray[nEventTotal] = sNew; nEventTotal++; } } else if(event.lNetworkEvents & FD_READ) // 处理FD_READ通知消息 { if(event.iErrorCode[FD_READ_BIT] == 0) { char szText[256]; int nRecv = recv(sockArray[i], szText, strlen(szText), 0); if(nRecv > 0) { szText[nRecv] = '\0'; printf("接收到数据:%s \n", szText); } } } else if(event.lNetworkEvents & FD_CLOSE) // 处理FD_CLOSE通知消息 { if(event.iErrorCode[FD_CLOSE_BIT] == 0) { closesocket(sockArray[i]); for(int j=i; j<nEventTotal-1; j++) { sockArray[j] = sockArray[j+1]; eventArray[j] = eventArray[j+1]; } nEventTotal--; } } else if(event.lNetworkEvents & FD_WRITE) // 处理FD_WRITE通知消息 { } } } } return 0; }
/* ************************************ *《精通Windows API》 * 示例代码 * Eventm.c * 7.2.1 演示使用Event同步线程 **************************************/ /* 头文件 */ #include <windows.h> #include <stdio.h> /* 常量定义 */ #define NUMTHREADS 3 #define BUFFER_SIZE 16 #define FOR_TIMES 5 /* 全局变量 */ HANDLE hWriteEvent[NUMTHREADS]; // 写Event 表示写操作是否完成 HANDLE hReadEvents[NUMTHREADS]; // 读Event 表示读操作是否完成 BYTE lpSharedBuffer[16] = {0}; // 共享内存 /* 函数声明 */ void MultiEvents(void); VOID WriteToBuffer(VOID); DWORD WINAPI ThreadFunction(LPVOID lpParam); /************************************* * int main(void) * 功能 演示 * * 参数 未使用 **************************************/ int main() { MultiEvents(); } /************************************* * void UseEvents(void) * 功能 演示Event的使用方法 * * 参数 未使用 **************************************/ void MultiEvents(void) { HANDLE hThread; DWORD i; // 创建多个线程,读共享内存,主线程写共享内存。 // 每个线程都有对应的读写同步事件 for(i = 0; i < NUMTHREADS; i++) { // 每个线程都有一个Event表示写入操作完成 hWriteEvent[i] = CreateEvent( NULL, // 默认安全属性 FALSE, // 自动重置 FALSE, // 初始为未置位的 NULL // 未命名 ); // 判断是否创建成功 if (hWriteEvent[i] == NULL) { printf("CreateEvent failed (%d)\n", GetLastError()); return; } // 每个读线程有一个Event表示读操作已经完成 hReadEvents[i] = CreateEvent( NULL, // 默认安全属性 FALSE, // 自动重置 FALSE, // 初始化为未置位的 NULL); // 未命名 if (hReadEvents[i] == NULL) { printf("CreateEvent failed (%d)\n", GetLastError()); return; } // 创建线程 hThread = CreateThread(NULL, 0, ThreadFunction, (LPVOID)i, // Event对象句柄作为 0, NULL); if (hThread == NULL) { printf("CreateThread failed (%d)\n", GetLastError()); return; } } WriteToBuffer(); } /************************************* * VOID WriteToBuffer(INT iContent) * 功能 由主线程调用,向共享内存中写入数据 * 等待所有读线程读完后函数返回 * * 参数 未使用 **************************************/ VOID WriteToBuffer(VOID) { DWORD dwWaitResult, j,i; // 完成 FOR_TIMES 次读写 for (j = 0; j < FOR_TIMES; j++) { Sleep(rand()%100); // 写入需要的时间随机 // 写入共享内存 wsprintf(lpSharedBuffer,"shared %d",j); // 将线程对应的写Event置为“标志的”,表示写操作完成, // 其他线程可以开始读 for(i=0; i<NUMTHREADS; i++) { if (! SetEvent(hWriteEvent[i]) ) { printf("SetEvent failed (%d)\n", GetLastError()); return; } } // 等待所有的线程读完,开始下次写入 dwWaitResult = WaitForMultipleObjects( NUMTHREADS, // Event句柄的个数 hReadEvents, // Event句柄数组 TRUE, // 等到所有的Event都被标志 INFINITE); // 无限等待 // 判断等待结果 if (dwWaitResult != WAIT_OBJECT_0) { printf("Wait error: %d\n", GetLastError()); ExitProcess(0); } } } /************************************* * DWORD WINAPI ThreadFunction(LPVOID lpParam) * 功能 线程函数,读共享内存 * * 参数 LPVOID lpParamt 实际为指向Event句柄的指针 **************************************/ DWORD WINAPI ThreadFunction(LPVOID lpParam) { DWORD dwWaitResult; BYTE lpRead[16]; DWORD j = 0; DWORD dwThreadIndex = (DWORD)lpParam; // 完成 FOR_TIMES 次读写 for(; j<FOR_TIMES; j++) { // 等待写事件置位,表示数据已经写入 dwWaitResult = WaitForSingleObject( hWriteEvent[dwThreadIndex], // Event 句柄 INFINITE); // 无限等待 switch (dwWaitResult) { case WAIT_OBJECT_0: Sleep(rand()%10); // 模拟数据处理所需的时间随机 CopyMemory(lpRead,lpSharedBuffer,16); break; // 发生错误 default: printf("Wait error: %d\n", GetLastError()); ExitThread(0); } // 将读Event置位,表示读操作完成 if (! SetEvent(hReadEvents[dwThreadIndex]) ) { printf("SetEvent failed (%d)\n", GetLastError()); return 0; } //打印读到的内容 printf("线程 %u\t第 %d 次读,内容:%s\n", dwThreadIndex,j,(LPSTR)lpRead); } return 1; }