Windows Overlapped I/O詳解

來源:互聯網
上載者:User

http://www.cnblogs.com/skyofbitbit/p/3650140.html

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<MAX_TRY_COUNT; 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 取得讀取資料完畢的使用者編號。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.