http://www.cnblogs.com/skyofbitbit/p/3650140.html
I/O設(shè)備處理必然讓主程序停下來干等I/O的完成, 對這個問題有 方法一:使用另一個線程進(jìn)行I/O,。這個方案可行,,但是麻煩。 即 CreateThread(…………),;創(chuàng)建一個子線程做其他事情,。 Readfile(^…………);阻塞方式讀數(shù)據(jù),。 方法二:使用overlapped I/O,。 overlapped I/O是WIN32的一項技術(shù),你可以要求操作系統(tǒng)為你傳送數(shù)據(jù),,并且在傳送完畢時通知你,。這項技術(shù)使你的程序在I/O進(jìn)行過程中仍然能夠繼續(xù)處理事務(wù)。事實上,,操作系統(tǒng)內(nèi)部正是以線程來I/O完成overlapped
I/O,。你可以獲得線程的所有利益,而不需付出什么痛苦的代價 怎樣使用overlapped I/O: 進(jìn)行I/O操作時,,指定overlapped方式 使用CreateFile (),,將其第6個參數(shù)指定為FILE_FLAG_OVERLAPPED, 就是準(zhǔn)備使用overlapped的方式構(gòu)造或打開文件; 如果采用 overlapped,,那么ReadFile(),、WriteFile()的第5個參數(shù)必須提供一個指針, 指向一個OVERLAPPED結(jié)構(gòu),。 OVERLAPPED用于記錄了當(dāng)前正在操作的文件一些相關(guān)信息,。 //功能:從指定文件的1500位置讀入300個字節(jié) int main() { BOOL rc; HANDLE hFile; DWORD numread; OVERLAPPED overlap; char buf[512]; char szPath=”c:\\xxxx\xxxx”; hFile = CreateFile( szPath, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, // 以overlapped打開文件 NULL ); // OVERLAPPED結(jié)構(gòu)實始化為0 memset(&overlap, 0, sizeof(overlap)); //指定文件位置是1500; overlap.Offset = 1500; rc = ReadFile(hFile,buf,300,&numread,&overlap); //因為是overlapped操作,ReadFile會將讀文件請求放入讀隊列之后立即返回(false),而不會等到文件讀完才返回(true) if (rc) { …………此處即得到數(shù)據(jù)了,。 //文件真是被讀完了,rc為true // 或當(dāng)數(shù)據(jù)被放入cache中,,或操作系統(tǒng)認(rèn)為它可以很快速地取得數(shù)據(jù),,rc為true } else { if (GetLastError() == ERROR_IO_PENDING) {//當(dāng)錯誤是ERROR_IO_PENDING,那意味著讀文件的操作還在進(jìn)行中 //等候,直到文件讀完 WaitForSingleObject(hFile, INFINITE); rc = GetOverlappedResult(hFile,&overlap,&numread,FALSE); //上面二條語句完成的功能與下面一條語句的功能等價: 一只阻塞等到得到數(shù)據(jù)才繼續(xù)下面,。 // GetOverlappedResult(hFile,&overlap,&numread,TRUE); } else { //出錯了 } } CloseHandle(hFile); return EXIT_SUCCESS; } 在實際工作中,,若有幾個操作同一個文件時, 怎么辦?我們可以利用OVERLAPPED結(jié)構(gòu)中提供的event來解決上面遇到的問題,。 注意,,你所使用的event對象必須是一個MANUAL型的;否則,,可能產(chǎn)生競爭條件,。 int main() { int i; BOOL rc; char szPath=”x:\\xxxx\xxxx”; // 以overlapped的方式打開文件 ghFile = CreateFile( szPath, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL ); for (i=0; i<MAX_REQUESTS; i++) requests 同時有N個同時讀取文件 { //將同一文件按幾個部分按overlapped方式同時讀 //注意看QueueRequest函數(shù)是如何運做的,每次讀16384個塊 QueueRequest(i, i*16384, READ_SIZE); } // 等候所有操作結(jié)束; //隱含條件:當(dāng)一個操作完成時,其對應(yīng)的event對象會被激活 WaitForMultipleObjects(MAX_REQUESTS, ghEvents, TRUE, INFINITE); // 收尾操作 for (i=0; i<MAX_REQUESTS; i++) { DWORD dwNumread; rc = GetOverlappedResult( ghFile, &gOverlapped[i], &dwNumread, FALSE ); CloseHandle(gOverlapped[i].hEvent); } CloseHandle(ghFile); return EXIT_SUCCESS; } //當(dāng)讀操作完成以后,,gOverlapped[nIndex].hEvent會系統(tǒng)被激發(fā) int QueueRequest(int nIndex, DWORD dwLocation, DWORD dwAmount) { //構(gòu)造一個MANUAL型的event對象 ghEvents[nIndex] = CreateEvent(NULL, TRUE, FALSE, NULL),; //將此event對象置入OVERLAPPED結(jié)構(gòu) gOverlapped[nIndex].hEvent = ghEvents[nIndex]; 每個重疊對象對應(yīng)一個事件。 gOverlapped[nIndex].Offset = dwLocation; for (i=0; i<MAX_TRY_COUNT; i++) //嘗試幾次。 { //文件ghFile唯一 rc = ReadFile(ghFile, gBuffers[nIndex],&dwNumread,&gOverlapped[nIndex]); if (rc) 如果立刻讀到數(shù)據(jù)則返回真 return TRUE; err = GetLastError(); if (err == ERROR_IO_PENDING) { //當(dāng)錯誤是ERROR_IO_PENDING,那意味著讀文件的操作還在進(jìn)行中 return TRUE; } // 處理一些可恢復(fù)的錯誤 if ( err == ERROR_INVALID_USER_BUFFER || err == ERROR_NOT_ENOUGH_QUOTA || err == ERROR_NOT_ENOUGH_MEMORY ) { sleep(50); continue;//重試 } // 如果GetLastError()返回的不是以上列出的錯誤,,放棄 break; } return -1; } 程序流程: 1: N個用戶同時讀取一個文件的各個部分,,且每個用戶對應(yīng)一個重疊對象和事件。 2:調(diào)用WaitForMultipleObjects(MAX_REQUESTS, ghEvents, TRUE, INFINITE) 當(dāng)任何一個用戶的讀操作完成時,,函數(shù)停止阻塞,。并且ghEvents中對應(yīng)于的讀取數(shù)據(jù)完畢的用戶的事件被激活。 3:調(diào)用GetOverlappedResult 取得讀取數(shù)據(jù)完畢的用戶編號,。
|