一、 同步I/O和异步I/O 代码:
DWORD nReadByte ; BYTE bBuf[BUF_SIZE] ; OVERLAPPED ov = { 0, 0, 0, 0, NULL } ; // hEvent = NULL ; HANDLE hFile = CreateFile ( ……, FILE_FLAG_OVERLAPPED, …… ) ; ReadFile ( hFile, bBuf, sizeof(bBuf), &nReadByte, &ov ) ; // 由于此时hEvent=NULL,所以同步对象为hFile,下面两句的效果一样 WaitForSingleObject ( hFile, INFINITE ) ; //GetOverlappedResult ( hFile, &ov, &nRead, TRUE ) ; 这段代码在调用ReadFile后会立即返回,但在随后的WaitForSingleObject或者GetOverlappedResult中阻塞,利用同步对象hFile进行同步。 代码:
DWORD nReadByte ; BYTE bBuf1[BUF_SIZE],bBuf2[BUF_SIZE],bBuf3[BUF_SIZE] ; OVERLAPPED ov1 = { 0, 0, 0, 0, NULL } ; OVERLAPPED ov2 = { 0, 0, 0, 0, NULL } ; OVERLAPPED ov3 = { 0, 0, 0, 0, NULL } ; HANDLE hFile = CreateFile ( ……, FILE_FLAG_OVERLAPPED, …… ) ; ReadFile ( hFile, bBuf1, sizeof(bBuf1), &nReadByte, &ov1 ) ; ReadFile ( hFile, bBuf2, sizeof(bBuf2), &nReadByte, &ov2 ) ; ReadFile ( hFile, bBuf3, sizeof(bBuf3), &nReadByte, &ov3 ) ; //假设三个I/O处理的时间比较长,到这里还没有结束 GetOverlappedResult ( hFile, &ov1, &nRead, TRUE ) ; 这里对于hFile有三个重叠的I/O操作,但他们的同步对象却都为hFile。使用GetOverlappedResult进行等待操作,这里看似在等待第一个I/O处理的完成,其实只要有任何一个I/O处理完成,该函数就会返回,相当于忽略了其他两个I/O操作的结果。 代码:
DWORD nReadByte ; BYTE bBuf1[BUF_SIZE],bBuf2[BUF_SIZE],bBuf3[BUF_SIZE] ; HANDLE hEvent1 = CreateEvent ( NULL, FALSE, FALSE, NULL ) ; HANDLE hEvent2 = CreateEvent ( NULL, FALSE, FALSE, NULL ) ; HANDLE hEvent3 = CreateEvent ( NULL, FALSE, FALSE, NULL ) ; OVERLAPPED ov1 = { 0, 0, 0, 0, hEvent1 } ; OVERLAPPED ov2 = { 0, 0, 0, 0, hEvent2 } ; OVERLAPPED ov3 = { 0, 0, 0, 0, hEvent3 } ; HANDLE hFile = CreateFile ( ……, FILE_FLAG_OVERLAPPED, …… ) ; ReadFile ( hFile, bBuf1, sizeof(bBuf1), &nReadByte, &ov1 ) ; ReadFile ( hFile, bBuf2, sizeof(bBuf2), &nReadByte, &ov2 ) ; ReadFile ( hFile, bBuf3, sizeof(bBuf3), &nReadByte, &ov3 ) ; //此时3个I/O操作的同步对象分别为hEvent1,hEvent2,hEvent3 GetOverlappedResult ( hFile, &ov1, &nRead, TRUE ) ; 这样,这个GetOverlappedResult就可以实现对第一个I/O处理的等待 代码:
VOID WINAPI APC_A ( DWORD dwError, DWORD cbTransferred, LPOVERLAPPED lpo ) { pTempInfo.push_back ( "执行IO_A的完成例程" ) ; } VOID WINAPI APC_B ( DWORD dwError, DWORD cbTransferred, LPOVERLAPPED lpo ) { pTempInfo.push_back ( "执行IO_B的完成例程" ) ; } VOID WINAPI APC_C ( DWORD dwError, DWORD cbTransferred, LPOVERLAPPED lpo ) { pTempInfo.push_back ( "执行IO_C的完成例程" ) ; } void CCompletionRoutineDlg::OnTest() { // TODO: Add your control notification handler code here HANDLE hFile_A, hFile_B, hFile_C ; OVERLAPPED ov_A = {0}, ov_B = {0}, ov_C = {0} ; #define C_SIZE 1024 * 1024 * 32 string szText_A = "Sample A !" ; string szText_B = "Sampel B !" ; string szText_C ; szText_C.resize ( C_SIZE ) ; memset ( &(szText_C[0]), 0x40, C_SIZE ) ; pTempInfo.clear () ; hFile_A = CreateFile ( "A.txt", GENERIC_WRITE, 0, NULL, \ CREATE_ALWAYS, FILE_FLAG_OVERLAPPED, NULL ) ; hFile_B = CreateFile ( "B.txt", GENERIC_WRITE, 0, NULL, \ CREATE_ALWAYS, FILE_FLAG_OVERLAPPED, NULL ) ; hFile_C = CreateFile ( "C.txt", GENERIC_WRITE, 0, NULL, \ CREATE_ALWAYS, FILE_FLAG_OVERLAPPED, NULL ) ; WriteFileEx ( hFile_A, &(szText_A[0]), szText_A.length(), &ov_A, APC_A ) ; pTempInfo.push_back ( "启动IO_A, 并立即返回" ) ; WriteFileEx ( hFile_B, &(szText_B[0]), szText_B.length(), &ov_B, APC_B ) ; pTempInfo.push_back ( "启动IO_B, 并立即返回" ) ; WriteFileEx ( hFile_C, &(szText_C[0]), szText_C.size(), &ov_C, APC_C ) ; pTempInfo.push_back ( "启动IO_C, 并立即返回" ) ; pTempInfo.push_back ( "进入可变等待状态" ) ; SleepEx ( 1, true ) ; pTempInfo.push_back ( "结束可变等待状态" ) ; pTempInfo.push_back ( "进入可变等待状态" ) ; SleepEx ( 10000, true ) ; pTempInfo.push_back ( "结束可变等待状态" ) ; CloseHandle ( hFile_A ) ; CloseHandle ( hFile_B ) ; CloseHandle ( hFile_C ) ; m_ListBox.ResetContent () ; list<string>::iterator p ; for ( p = pTempInfo.begin(); p != pTempInfo.end(); p++ ) { m_ListBox.AddString ( p->data() ) ; } DeleteFile ( "A.txt" ) ; DeleteFile ( "B.txt" ) ; DeleteFile ( "C.txt" ) ; } 执行后的效果如下(WinXP+SP2+VC6.0): 代码:
UINT ServerThread ( LPVOID lpParameter ) { …… while ( true ) { GetQueuedCompletionStatus ( pMyDlg->hCompletionPort, &cbTrans, &dwCompletionKey, &lpov, INFINITE ) ; if ( dwCompletionKey == -1 ) break ; // 读取管道信息 // 响应管道信息(写入) } return 0 ; } void CMyDlg::OnStart() { // 创建完成端口 hCompletionPort = CreateIoCompletionPort ( INVALID_HANDLE_VALUE, NULL, 0, nMaxThread ) ; CString lpPipeName = "\\\\.\\Pipe\\NamedPipe" ; for ( UINT i = 0; i < nMaxPipe; i++ ) { // 创建命名管道 PipeInst[i].hPipe = CreateNamedPipe ( lpPipeName, PIPE_ACCESS_DUPLEX|FILE_FLAG_OVERLAPPED, \ PIPE_TYPE_BYTE|PIPE_READMODE_BYTE|PIPE_WAIT, nMaxPipe, 0, 0, INFINITE, NULL ) ; …… // 把命名管道与完成端口关联起来 HANDLE hRet = CreateIoCompletionPort ( PipeInst[i].hPipe, hCompletionPort, i, nMaxThread ) ; …… // 等待连接 ConnectNamedPipe ( PipeInst[i].hPipe, &(PipeInst[i].ov) ) ; } // 创建线程 for ( i = 0; i < nMaxThread; i++ ) { hThread[i] = AfxBeginThread ( ServerThread, NULL, THREAD_PRIORITY_NORMAL ) ; } …… } void CMyDlg::OnStop() { for ( UINT i = 0; i < nMaxThread; i++ ) { // 用来唤醒线程的虚假I/O完成包 PostQueuedCompletionStatus ( hCompletionPort, 0, -1, NULL ) ; CloseHandle ( hThread[i] ) ; } for ( i = 0; i < nMaxPipe; i++ ) { DisconnectNamedPipe ( PipeInst[i].hPipe ) ; CloseHandle ( PipeInst[i].hPipe ) ; } …… } 4、心得体会 |