天天看點

Poedu_Windows_異步IO(2)

異步IO

使用異步IO的四種提醒方式

1.使用裝置核心對象進行提醒
進行異步檔案操作的提醒
2.使用事件核心對象提醒
提醒同步以及互動,是一種完全不同的的提醒
3.可提醒IO
不可跨線程的
4.I/O完成端口
使用最廣泛

使用事件核心對象提醒

示例
#include<windows.h>
int main()
{
  HANDLE hFile =CreateFile(TEXT("demo.txt",GENERIC_READ|GENERAIC_WRITE,FILE_SHARE,nullptr,OPEN_ALWAYS,FILE_FALG_OVERLAPPED,NULL);
  if(hFile != INVALID_HANDLE_VALUE)
  {
      //read
      BYTE bReadBuffer[]={};

      OVERLAPPED oRead ={};
      oRead.Offset=;
      oRead.hEvent = CreateEvent(nullptr,TRUE,FALSE,TEXT("ReadEvent"));//事件核心對象,是獨立于程式之外的,屬于作業系統的,通過name在各個程式中使用
      ReadFile(hFile,bReadBuffer,sizeof(bReadBuffer),nullptr,&oRead);

      //write
      BYTE bWriteBuffer[]={};

      OVERLAPPED oWrite ={};
      oWrite.Offset=;
      oWrite.hEvent = CreateEvent(nullptr,TRUE,FALSE,TEXT("WriteEvent"));//事件核心對象,是獨立于程式之外的,屬于作業系統的,通過name在各個程式中使用
      WriteFile(hFile,bWriteBuffer,sizeof(bWriteBuffer),nullptr,&oWrite);

      //做其它的事情...異步最好的地方,就在于不會發生阻塞
      //其它線程
      HANDLE hOverLapped[]={};
      hOverLapped[]=oRead.hEvent;
      hOverLapped[]=oWrite.hEvent;

       while (TRUE)
        {
            DWORD dwCase = WaitForMultipleObjects(, hOverLapped, FALSE, INFINITE);//進行事件對象的提醒
            switch (dwCase - WAIT_OBJECT_0)
            {
            case :
                // 讀完成
                break;
            case :
                // 寫完成
                break;
            }
        }
  }
  else
  {
      //GetLastError
  }
}
           
程式領空與系統領空
系統領空是所有程式共用的,事件核心對象存在于系統領空,那麼程式與程式之間的互動就可以通過事件核心對象,也可以通過事件核心對象中的對象來判斷狀态

可提醒IO

事件核心對象提醒:

發送請求

做自己的事情

判斷請求是否完成

可提醒IO:

發送請求

完成後,作業系統提醒我

APC機制

程序是工廠,線程是勞工,線上程的内部,它有一個機制:APC

當勞工閑的時候(前提),來做APC清單中的事情
當線程空閑的時候(線程為可提醒狀态下),自動執行APC清單中的事情
比如:MessageBox會導緻線程阻塞,當這個線程阻塞的時候,看上去線程閑下來了,但是并不是可提醒狀态,在windows中,隻有Wait函數、Sleep函數才能真正的“閑”下來

相當于一個不定時的定時器,APC不确定啥時候會被觸發,但是隻要觸發就會去做事情

提醒IO就是依托于APC來做的

示例

#include<windows.h>
int main()
{
  HANDLE hFile =CreateFile(TEXT("demo.txt",GENERIC_READ|GENERAIC_WRITE,FILE_SHARE,nullptr,OPEN_ALWAYS,FILE_FLAG_OVERLAPPED,NULL));
  if(hFile != INVALID_HANDLE_VALUE)
  {
     CONST UINT unLen = ;
        // Read
        OVERLAPPED oRead = {};//此時裡面的東西都不用設定,Offset可以設定,但是Event不能設定
        oRead.Offset = ;
        BYTE bReadBuf[unLen] = {};
        // 異步讀取檔案 通過可提醒IO
        ReadFileEx(hFile,  bReadBuf, unLen,  &oRead,FileIOCommpletionRoutineRead);
        // 可以使得線程為可提醒狀态的函數
            // SleepEx
            // Wait.... 函數
        SleepEx(, TRUE);//BOOL值代表,當SleepEx被調用的時候,是否把自己設定為空閑狀态,不設定為TRUE的時候,也就相當于阻塞但非可提醒狀态,此時APC不會被調用,是以這個BOOL值很重要
  }
  else
  {
      //GetLastError
  }
}
           
可提醒不是那麼好用:
回調函數參數太少,作用有限,可通過全局來傳入參數,但是邏輯會混亂

完成端口機制

操作異步IO最為友善、科學的方式
以上三種都是一個線程之内來做的事情,可提醒IO可以讓别的線程來做這件事情,但是做起來較為麻煩,使用的是串行模型來進行異步IO操作

異步IO操作最适合的是并行模式,是多線程。

windows是多程序的

但是在單核時代,是模拟出來的多程序,隻是CPU運作速度快,我們沒感覺而已

多核下,每個核都可以運作一個線程(無切換), 也可以進行線程切換

多程序
如果程序隻有一個線程,那麼一個程式隻能做一件事情,如果需要做兩件事情,那麼就需要兩個程序,但是,兩個程序都會有一個核心對象,如果兩個程序進行互動的話,那麼會耗費大量的資源,是以在程序之下設計了線程
多線程
線程之間的切換也會耗費資源,隻是比線程之間切換要好點。核心數增加之後,并行模式開始流行起來
完成端口是天生的并行模式,使用它來異步操作大檔案的時候會更快

未完待續…

如有錯誤,煩請指出..

繼續閱讀