青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

兔子的技術博客

兔子

   :: 首頁 :: 聯系 :: 聚合  :: 管理
  202 Posts :: 0 Stories :: 43 Comments :: 0 Trackbacks

留言簿(10)

最新評論

閱讀排行榜

評論排行榜

標 題: Windows系統編程之異步I/O和完成端口
作 者: 北極星2003
時 間: 2006-07-02 18:46 
鏈 接: http://bbs.pediy.com/showthread.php?threadid=28342 
詳細信息:

 

Windows系統編程之異步I/O和完成端口
【作者】北極星2003
【來源】看雪技術論壇(bbs.pediy.com) 
【時間】2006年7月1日

一、  同步I/O和異步I/O

在介紹這部分內容之前先來認識下“異步I/O”。
  說起異步IO,很容易聯想到同步I/O,對于同一個I/O對象句柄在同一時刻只允許一個I/O操作,其原理如下圖所示:
 

  顯然,當內核真正處理I/O的時間段(T2~T4),用戶線程是處于等待狀態的,如果這個時間段比較段的話,沒有什么影響;倘若這個時間段很長的話,線程就會長時間處于掛起狀態。事實上,該線程完全可以利用這段時間用處理其他事務。

  異步I/O恰好可以解決同步I/O中的問題,而且支持對同一個I/O對象的并行處理,其原理如下圖所示:
 

  異步I/O在I/O請求完成時,可以使用讓I/O對象或者事件對象受信來通知用戶線程,而用戶線程中可以使用GetOverlappedResult來查看I/O的執行情況。
  
由于異步I/O在進行I/O請求后會立即返回,這樣就會產生一個問題:“程序是如何取得I/O處理的結果的?”。

  有多種方法可以實現異步I/O,其不同資料上的分類一般都不盡相同,但原理上都類似,這里我把實現異步I/O的方法分為3類,本文就針對這3類方法進行詳細的討論。
(1)重疊I/O
(2)異步過程調用(APC),擴展I/O
(3)使用完成端口(IOCP)

二、使用重疊I/O實現異步I/O
  
  同一個線程可以對多個I/O對象進行I/O操作,不同的線程也可以對同一個I/O對象進行操作,在我的理解中,重疊的命名就是這么來的。

  在使用重疊I/O時,線程需要創建OVERLAPPED結構以供I/O處理。該結構中最重要的成員是hEvent,它是作為一個同步對象而存在,如果hEvent為NULL,那么此時的同步對象即為文件句柄、管道句柄等I/O操作對象。當I/O完成后,會使這里的同步對象受信,從而通知用戶線程。

  由于在進行I/O請求后會立即返回,但有時用戶線程需要知道I/O當前的執行情況,此時就可以使用GetOverlappedResult。如果該函數的bWait參數為true,那么改函數就會阻塞線程直到目標I/O處理完成為止;如果bWait為false,那么就會立即返回,如果此時的I/O尚未完,調用GetLastError就會返回ERROR_IO_INCOMPLETE。

代碼示例一:

代碼:
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進行同步。

  這段代碼在這里可以實現正常的異步I/O,但存在一個問題,倘若現在需要對hFile句柄進行多個I/O操作,就會出現問題。見下面這段代碼。

代碼示例二:

代碼:
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操作的結果。

  其實,這里有一個很重要的原則:對于一個重疊句柄上有多于一個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處理的等待
關于重疊I/O的就討論到這里,關于重疊I/O的實際應用,可以參考《Windows系統編程之進程通信》其中的命名管道實例。
http://bbs.pediy.com/showthread.php?s=&threadid=26252
 
三、  使用異步過程調用實現異步I/O

異步過程調用(APC),即在特定的上下文中異步的執行一個調用。在異步I/O中可以使用APC,即讓操作系統的IO系統在完成異步I/O后立即調用你的程序。(在有些資料中,把異步I/O中的APC稱為“完成例程”,感覺這個名稱比較貼切,下文就以“完成例程”來表述。另外通常APC是作為線程同步這一塊的內容,這里盡量淡化這個概念以免混淆。關于APC的詳細內容到線程同步時再介紹 )

這里需要注意三點:
(1)  APC總是在調用線程中被調用;
(2)  當執行APC時,調用線程會進入可變等待狀態;
(3)  線程需要使用擴展I/O系列函數,例如ReadFileEx,WriteFileEx, 另外可變等待函數也是必須的(至少下面其中之一):
WaitForSingleObjectEx
WaitForMultipleObjectEx
SleepEx
SignalObjectAndWait
MsgWaitForMultipleObjectsEx
  
  在使用ReadFileEx,WriteFileEx時,重疊結構OVERLAPPED中的hEvent成員并非一定要指定,因為系統會忽略它。當多個IO操作共用同一個完成例程時,可以使用hEvent來攜帶序號等信息,用于區別不同的I/O操作,因為該重疊結構會傳遞給完成例程。如果多個IO操作使用的完成例程都不相同時,則直接把hEvent設置為NULL就可以了。

在系統調用完成例程有兩個條件:
(1)  I/O操作必須完成
(2)  調用線程處于可變等待狀態

對于第一個條件比較容易,顯然完成例程只有在I/O操作完成時才調用;至于第二個條件就需要進行認為的控制,通過使用可變等待函數,讓調用線程處于可變等待狀態,這樣就可以執行完成例程了。這里可以通過調節調用可變等待函數的時機來控制完成例程的執行,即可以確保完成例程不會被過早的執行。

當線程具有多個完成例程時,就會形成一個隊列。使用可變等待函數使線程進入可變等待狀態時有一個表示超時值的參數,如果使用INFINITE,那么只有所有排隊的完成例程被執行或者句柄獲得信號時該等待函數才返回。

上面已經對利用完成例程實現異步I/O的一些比較重要的細節進行的簡潔的闡述,接下來就以一個實例來說明完成例程的具體實現過程。



實例一:使用完成例程的異步I/O示例

1、  設計目標
體會完成例程的異步I/O實現原理及過程。

2、  問題的分析與設計
設計流程圖如下:
 
示圖說明:
  三個IO操作分別是IO_A, IO_B, IO_C, 他們的完成例程分別是APC_A, APC_B, APC_C。IO_A, IO_B是兩個很短的IO操作,IO_C是一個比較費時的IO操作。
3、  詳細設計(關鍵代碼如下,具體參見附件中的源代碼CompletionRoutine)

代碼:
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):
 

4、  心得體會
每當一個IO操作結束時會產生一個完成信息,如果該IO操作有完成例程的話就添加到完成例程隊列。一旦調用線程進入可變等待狀態,就會依次執行隊列中的完成例程。
在這個示例中還有一個問題,如果把這個軟件放在系統分區的文件目錄下可以正常執行,而放在其他盤符下就會出現問題,執行結果就不同,真是奇怪了。


四、使用完成端口(IOCP)

實例二、使用IOCP的異步I/O示例
1、設計目標
體會完成端口的異步I/O實現原理及過程。

2、  問題的分析與設計


說明:
  每個客戶端與一個管道進行交互,而在交互過程中I/O操作結束后產生的完成包就會進入“I/O完成包隊列”。完成端口的線程隊列中的線程使用GetQueuedCompletionStatus來檢測“I/O完成包隊列”中是否有完成包信息。 
3、詳細設計(關鍵代碼如下,具體見附件中的源碼)

代碼:
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、心得體會
  上面這個例子是關于完成端口的簡單應用。可以這樣來理解完成端口,它與三種資源相關分別是管道、I/O完成包隊列、線程隊列,它的作用是協調這三種資源。
【參考文獻】
[1]. Windows系統編程. Johnson M.Hart著
【版權聲明】必須注明來源看雪技術論壇(bbs.pediy.com) 及作者,并保持文章的完整性。


轉自:http://andylin02.iteye.com/blog/476399
posted on 2011-06-29 10:13 會飛的兔子 閱讀(630) 評論(0)  編輯 收藏 引用 所屬分類: 系統API,底層技術
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            韩国v欧美v日本v亚洲v| 亚洲精品在线视频观看| 亚洲精品一区二区三区福利| 亚洲精品影院在线观看| 国产精品va在线| 新片速递亚洲合集欧美合集| 久久狠狠婷婷| 日韩特黄影片| 欧美中文在线观看| 一本久久青青| 一区二区三区av| 激情久久久久久久| 日韩一区二区久久| 狠狠综合久久av一区二区小说| 亚洲欧洲久久| 欧美极品一区二区三区| 欧美在线国产| 欧美日韩免费观看一区三区| 久久深夜福利免费观看| 欧美日韩国产成人高清视频| 老鸭窝亚洲一区二区三区| 欧美三级韩国三级日本三斤| 蜜桃久久av一区| 国产精品日本欧美一区二区三区| 欧美激情一区二区三区高清视频 | 国产精品一区2区| 亚洲激情午夜| 在线观看国产精品网站| 亚洲天堂成人| 在线一区二区日韩| 亚洲日本va午夜在线电影| 亚洲淫性视频| 久久亚洲精选| 欧美在线视频全部完| 欧美午夜精品理论片a级大开眼界| 欧美国产日韩a欧美在线观看| 国产伦理一区| 亚洲网站视频福利| 中文一区字幕| 免费欧美视频| 久久裸体艺术| 国产色产综合产在线视频| 日韩写真在线| 亚洲另类在线视频| 久久久久久一区二区| 欧美综合国产精品久久丁香| 亚洲免费观看高清完整版在线观看熊 | 亚洲精品日韩欧美| 亚洲第一在线综合网站| 久久精品国产v日韩v亚洲| 欧美一站二站| 国产日韩欧美精品| 性一交一乱一区二区洋洋av| 亚久久调教视频| 国产乱码精品一区二区三| 亚洲永久视频| 性欧美长视频| 国产老肥熟一区二区三区| 亚洲欧美视频一区二区三区| 午夜精品久久久久影视| 国产伦精品一区二区三区四区免费 | 亚洲在线成人精品| 亚洲一区自拍| 欧美午夜在线一二页| 一区二区三区四区蜜桃| 亚洲字幕一区二区| 国产精品一区二区在线| 欧美一级视频精品观看| 久热精品视频在线观看一区| 亚洲成色精品| 欧美黄色精品| 亚洲四色影视在线观看| 欧美在线日韩| 亚洲高清久久| 欧美人成在线| 亚洲欧美另类久久久精品2019| 欧美一区二区在线观看| 国内在线观看一区二区三区| 久久成年人视频| 欧美激情亚洲另类| 一区二区三区视频在线播放| 国产精品二区二区三区| 久久不见久久见免费视频1| 欧美成人性生活| 亚洲无线一线二线三线区别av| 国产精品大片wwwwww| 久久久久久噜噜噜久久久精品| 亚洲欧洲一区二区三区| 亚洲在线一区二区| 在线观看91精品国产入口| 欧美国产精品专区| 午夜国产欧美理论在线播放 | 99在线精品免费视频九九视| 欧美日韩国产小视频| 亚洲一级特黄| 理论片一区二区在线| 亚洲调教视频在线观看| 国产偷久久久精品专区| 欧美高清影院| 午夜日韩激情| 91久久一区二区| 欧美专区福利在线| 一区二区三区日韩精品| 在线观看日韩专区| 国产精品成人观看视频国产奇米| 欧美日韩国产欧| 久久aⅴ乱码一区二区三区| 久久久视频精品| 99在线热播精品免费99热| 久久久久成人精品| 一区二区三区日韩在线观看| 尤物99国产成人精品视频| 国产精品久久久久久久免费软件 | 亚洲黄色性网站| 国产欧美一区二区三区久久 | 亚洲人成在线观看网站高清| 久久精品国产欧美激情| 99在线精品观看| 在线观看av一区| 国产视频观看一区| 欧美性视频网站| 欧美激情精品久久久| 久久久精品国产99久久精品芒果| 国产精品户外野外| 久久aⅴ国产欧美74aaa| 在线天堂一区av电影| 亚洲成色777777在线观看影院| 国产午夜精品一区二区三区视频| 欧美日韩亚洲一区二| 欧美黄色一级视频| 嫩草伊人久久精品少妇av杨幂| 久久成人免费| 久久成人免费日本黄色| 欧美在线日韩在线| 午夜欧美理论片| 欧美一区二区高清| 性欧美1819sex性高清| 亚洲一区二区三区四区中文| 一二三区精品| 亚洲天堂视频在线观看| 亚洲深夜福利视频| 中文久久乱码一区二区| 在线中文字幕日韩| 亚洲午夜免费视频| 亚洲一区影音先锋| 亚洲午夜黄色| 性色一区二区| 久久黄色影院| 乱人伦精品视频在线观看| 模特精品裸拍一区| 欧美日韩精品一本二本三本| 欧美四级在线| 国产老女人精品毛片久久| 国产区日韩欧美| 激情成人综合| 最新国产成人av网站网址麻豆 | 中文国产一区| 亚洲专区在线视频| 欧美在线影院在线视频| 久久夜色精品一区| 欧美黑人国产人伦爽爽爽| 欧美精品一区二区三区四区| 欧美精品免费在线| 欧美午夜一区二区| 国产欧美日韩精品一区| 国产午夜精品在线| 亚洲国产美女| 亚洲在线观看视频| 久久综合色88| 91久久久久久久久| 国产精品日韩久久久久| 亚洲精品久久久久久久久久久久久 | 亚洲日本中文| 亚洲欧美日韩在线观看a三区| 欧美一区二区三区四区视频| 久久青草久久| 亚洲精品资源| 欧美一区二区三区视频| 久久综合伊人77777麻豆| 欧美日韩国产综合在线| 国产香蕉久久精品综合网| 亚洲国产欧美一区| 亚洲网站在线播放| 久久gogo国模啪啪人体图| 欧美激情一区在线观看| 在线亚洲一区| 免费成人av| 国产美女精品视频| 亚洲美女淫视频| 久久久精品动漫| 亚洲精品无人区| 久久久精品五月天| 国产精品久久久久久av下载红粉| 亚洲高清视频在线观看| 亚洲午夜视频| 男女av一区三区二区色多| 亚洲一二三区在线| 欧美黄色aa电影| 亚洲第一毛片| 一区二区三欧美|