在Linux下編寫非同步I/O的模型探討

來源:互聯網
上載者:User

在Linux下編寫非同步I/O的模型探討

需要首先說明的是非同步I/O和多工同步I/O(如通過select函數在串連池中選擇任一完成的連接埠)是有本質差異的,雖然兩種方式都能提高效率。
非同步I/O的思想是在一個連接埠支援非同步讀寫,讀寫非同步系統調用需要OS支援,比如Read、Write有非同步實現版本,則使用者調用其Read、Write非同步版本,如果連接埠暫時不可用,會立即返回到使用者代碼。可以針對同一個連接埠準備多個非同步讀寫操作,充分利用連接埠資源以及減少使用者在等待連接埠可用過程中被掛起的時間。

一、Windows下的非同步I/O的模型
通過OVERLAPPED structure和WaitForMultipleObjects/WaitForMultipleEvents實現。
範例程式碼如下:

HANDLE hfile = CreateFile(..., FILE_FLAG_OVERLAPPED, ...);

BYTE bBuffer[10]; 
OVERLAPPED oRead = { 0 };
oRead.Offset = 0;
oRead.hEvent = CreateEvent(...);
ReadFile(hfile, bBuffer, 10, NULL, &oRead);

OVERLAPPED oWrite = { 0 };
oWrite.Offset = 10;
oWrite.hEvent = CreateEvent(...);
WriteFile(hfile, "Jeff", 5, NULL, &oWrite);
 

HANDLE h[2];
h[0] = oRead.hEvent;
h[1] = oWrite.hEvent;
DWORD dw = WaitForMultipleObjects(2, h, FALSE, INFINITE);
switch (dw _ WAIT_OBJECT_0) {
   case 0:   // Read completed
      break;

   case 1:   // Write completed
      break;
}

二、Linux下的非同步I/O的模型
在Linux下不存在OVERLAPPED structure及WaitForMultipleObjects/WaitForMultipleEvents等系統調用,所以需要自行封裝一些函數,以方便實現非同步作業。
本課題基於Linux在核心實現了POSIX1003.1b標準定義的非同步I/O函數。基本思想是當一個進程有非同步I/O請求時,就為該進程建立一個隊列來排隊其所有的非同步請求,並為該隊列建立一個核心線程來完成隊列中實際的I/O操作。非同步I/O系統調用所做的工作只是將I/O請求加入調用進程的隊列,如果調用該功能的進程是第一次發出非同步I/O請求,則先要為該進程建立排隊非同步I/O請求的隊列和相應的核心線程,然後進程直接返回而不用掛起等待I/O完成。當實際的I/O操作完成時,核心發一個訊號通知進程I/O完成。
2.1 非同步請求控制塊aiocb
該結構是非同步I/O系統調用的主要參數,其中包含了非同步作業所需的所有資訊,是最基本也是最重要的資料結構,包括要進行的操作(讀或寫)及其優先順序,被請求的檔案描述符、位移量、位元組數,緩衝區地址等。
Struct aiocb
{
/*下面7項成員的值由使用者提供,用來確定非同步I/O請求的各個參數*/
intaiofildes;/*檔案描述符*
/intaiolioopcode;/*I/O操作類型*/
intaioreqprio;/*優先順序*/
void* aiobuf;/*緩衝區*/
size_t aionbytes;/*位元組數*/
struct sigevent aiosigevent;/*訊號量*/
loff_t aiooffset;/*檔案位移量*/
/*下面這些是內部成員,使用者不需提供*/
Kaio_key_t aiokey;
Unsigned long aiotimes;/*實際I/O完成的時間*/
int aioerror;/*aioerror的傳回值*/
ssize_t aioreturn;/*aioreturn的傳回值*/
}

2.2 核心非同步請求控制塊kaiocb
該結構是提供給核心的非同步I/O資訊,包含結構aiocb中的所有資訊以及其它一些相關的資料結構。
Structkaiocb
{
Struct aiocb* kaiouaiocb;/*使用者提供的aiocb*/
Struct file* kaiofilp;
void* kaiobuf;
size_t kaionbytes;
loff_t kaiooffset;
int kaiocmd;/*I/O操作:read|write|fsync*/
int kaioerror;
int kaioid;/*kaiocb描述符*/
struct kaiocb* kaiohnext;/*hash表後指標*/
struct kaiocb** kaiohpprev;/*hash表前指標*/
struct liocb *kaioliocb;/*ListI/O控制塊指標*/
struct waitqueue **kaiosuspendwait;
struct taskstruct *kaiotask;/*提出請求的進程*/
struct kaio_list_head_kaio_ioq;/*非同步請求隊列頭指標*/
void*kaiokq;/*非同步請求隊列*/
struct sigevent kaiosigevent;/*通知訊號量*/
unsigned long kaiotimes[AIOTIMES];
#definek aiosettime(k,x)(k)->kaiotimes[(x)]=kaiotime()
}
2.3 非同步請求隊列
該隊列是一個雙向迴圈鏈表。每個有非同步請求的進程建立一個非同步請求隊列,該進程的所有非同步請求都在該隊列中排隊。
Struct kaio_queue
{
Spinlock_t kaioq_lock;
Structkaiolisthead kaioq;
Int kaioqref;
Int threads;
}
2.4 演算法
以非同步讀aioread為例,該函數的功能是根據非同步I/O控制塊aiocb所提供的資訊將指定的檔案內容拷貝到指定的緩衝區中。
演算法 aioread
輸入:非同步I/O、控制塊aiocb
輸出:成功返回0,失敗返回-1
{
if(進程第一次發出非同步請求,還沒有非同步請求隊列)
為之建立一個非同步請求隊列kq;
if(當前的非同步請求數目大於系統規定的最大值)
出錯返回;
if(aiocb指定的檔案不合法)
出錯返回;
根據aiocb設定核心非同步I/O控制塊kiocb各個域的值;
調用kaiocbenqueue將請求入隊;
if(入隊操作失敗返回)
出錯返回;
函數返回;
}

演算法 kaiocbenqueue
輸入:非同步請求隊列kq、核心非同步I/O控制塊kaiocb
輸出:成功返回0,失敗返回相應的錯誤號碼
{
將kaiocb插入非同步請求隊列kq的相應位置;
if(kq還沒有進行具體I/O操作的核心服務線程)
調用kernelthread(handleio,kaiocb,0)為之建立一個核心線程; (其中handleio是線程的執行函數);
函數返回;
}


演算法 handleio
輸入:核心非同步I/O控制塊kaiocb
輸出:成功返回0,失敗返回相應的錯誤號碼
{
while(隊列不空)
{
執行檔案底層的I/O操作fop->read;
操作完成後將該請求從隊列中刪除;
}
給進程kaiocb->kaiotask發訊號kaiocb->kaiosigevent,通知進程I/O操作完成;
函數返回;

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.