重疊IO overlapped I/O 運用詳解

轉自:http://blog.chinaunix.net/uid-13408389-id-2894916.html



重疊IO overlapped I/O 運用詳解
2009年02月21日 星期六 下午 07:54

I/O設備處理必然讓主程序停下來乾等I/O的完成,
對這個問題有

方法一:使用另一個線程進行I/O。這個方案可行,但是麻煩。                即 CreateThread(…………);創建一個子線程做其他事情。     Readfile(^…………);阻塞方式讀數據。

方法二:使用overlapped I/O。
overlapped I/O是WIN32的一項技術, 你可以要求操作系統爲你傳送數據,並且在傳送完畢時通知你。這項技術使你的程序在I/O進行過程中仍然能夠繼續處理事務。事實上,操作系統內部正是以線程來I/O完成overlapped I/O。你可以獲得線程的所有利益,而不需付出什麼痛苦的代價
   

怎樣使用overlapped I/O:

進行I/O操作時,指定overlapped方式
使用CreateFile (),將其第6個參數指定爲FILE_FLAG_OVERLAPPED,
就是準備使用overlapped的方式構造或打開文件;
如果採用 overlapped,那麼ReadFile()、WriteFile()的第5個參數必須提供一個指針,

指向一個OVERLAPPED結構。 OVERLAPPED用於記錄了當前正在操作的文件一些相關信息。

//功能:從指定文件的1500位置讀入300個字節
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結構實始化爲0
    memset(&overlap, 0, sizeof(overlap));
    //指定文件位置是
1500;
    overlap.Offset = 1500;
    
    rc = ReadFile(hFile,buf,300,&numread,&overlap);
    //因爲是overlapped操作,ReadFile會將讀文件請求放入讀隊列之後立即返回(false),而不會等到文件讀完才返回
(true)
    if (rc)
    {

…………此處即得到數據了。
       //文件真是被讀完了,rc爲true
       // 或當數據被放入cache中,或操作系統認爲它可以很快速地取得數據,rc爲
true
    }
    else
    {
        if (GetLastError() == ERROR_IO_PENDING)
        {//當錯誤是ERROR_IO_PENDING,那意味着讀文件的操作還在進行中

         //等候,直到文件讀完
            WaitForSingleObject(hFile, INFINITE);
            rc = GetOverlappedResult(hFile,&overlap,&numread,FALSE);
            //
上面二條語句完成的功能與下面一條語句的功能等價:

一隻阻塞等到得到數據才繼續下面。
            // GetOverlappedResult(hFile,&overlap,&numread,TRUE);
         }
         else
         {
            //
出錯了
        }
    }
    CloseHandle(hFile);
    return EXIT_SUCCESS;
}

在實際工作中,若有幾個操作同一個文件時,
怎麼辦?我們可以利用OVERLAPPED結構中提供的event來解決上面遇到的問題。

注意,你所使用的event對象必須是一個MANUAL型的;否則,可能產生競爭條件。
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函數是如何運做的,每次讀16384個塊
        QueueRequest(i, i*16384, READ_SIZE);
    }
    // 
等候所有操作結束;
    //隱含條件:當一個操作完成時,其對應的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;
}

//當讀操作完成以後,gOverlapped[nIndex].hEvent會系統被激發
int QueueRequest(int nIndex, DWORD dwLocation, DWORD dwAmount)
{
    //
構造一個MANUAL型的event對象
    ghEvents[nIndex] = CreateEvent(NULL, TRUE, FALSE, NULL)
    //將此event對象置入OVERLAPPED結構
    gOverlapped[nIndex].hEvent = ghEvents[nIndex];

每個重疊對象對應一個事件。
    gOverlapped[nIndex].Offset = dwLocation;
    for (i=0; i
嘗試幾次。
   {
      //
文件ghFile唯一
       rc = ReadFile(ghFile, gBuffers[nIndex],&dwNumread,&gOverlapped[nIndex]);
       if (rc) 
如果立刻讀到數據則返回真
         return TRUE;
       err = GetLastError();
       if (err == ERROR_IO_PENDING)
       {
           //
當錯誤是ERROR_IO_PENDING,那意味着讀文件的操作還在進行中
          return TRUE;
       }
       // 
處理一些可恢復的錯誤
       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個用戶同時讀取一個文件的各個部分,且每個用戶對應一個重疊對象和事件。

2:調用WaitForMultipleObjects(MAX_REQUESTS, ghEvents, TRUE, INFINITE) 當任何一個用戶的讀操作完成時,函數停止阻塞。並且ghEvents中對應於的讀取數據完畢的用戶的事件被激活。

3 調用GetOverlappedResult 取得讀取數據完畢的用戶編號。


發佈了18 篇原創文章 · 獲贊 26 · 訪問量 12萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章