使用I/O完成端口模型监测磁盘文件状态

作者:Frank

众所周知,I/O完成端口(IOCP)是目前性能最好的一种I/O模型。其大体的思路如下:在程序处理的过程中,阻塞类型的操作有很多,如(Socket Send/Recv), 磁盘读写,外部硬件接口(如打印机,扫描仪)等;以往的模型在处理阻塞事件时,为了提高程序在阻塞同时的并发性,经常使用多线程,这样就有很多可调度的线程并行在系统中,OS内核会花费大量的时间在线程的Context切换中,线程本身工作处理的时间会很少(可称工作饱和度很低),极端的情况下线程切换的时间甚至可能会大于本身线程的运行周期。

IOCP模型是windows提供的一种阻塞事件异步处理的模型,应用程序可以根据CPU的核数预先开N个线程,存储在线程池中。然后将所有的I/O请求都投递到一个完成端口上,与此同时N个工作线程逐一地从完成端口中读取完成的阻塞事件并加以处理,这样就极大程度的提高了线程的工作饱和度。

目前在性能上号称数倍优于Apache的服务器模型nginx,其实使用的也是这种机制,只是windows内部支持完成端口,而linux的支持为epool,所有的请求简化为阻塞操作和非阻塞操作,所有需要阻塞请求的部分全部由epool触发相应事件,非阻塞(处理耗时短)部分用主线程一直执行,直到遇到阻塞部分就停止,交由阻塞部分监听异步完成事件,这样就构成了nginx中的事件驱动模型。

平时讨论的比较多的是网络服务模型,即在server端使用IOCP管理socket链接,其实IOCP是可以应用于所有支持异步执行的阻塞操作中,下面介绍一个用来监测文件状态的实例:

应用场景之一:很多网盘应用提供同步功能,由于大家时常进行本地文件和网盘文件的upload/download操作,这样很不方便,设定同步功能可以自动将其关联,实现文件的实时更新,用户也体验大大提高。

代码使用VS2008实现,提供一个cFileUpdateChecker类,可以指定监测路径,每当其路径发生变化都会获取到通知事件,如copy, paste, create, remove, renaming, property modification等等,使用Windows API : ReadDirectoryChangesW的异步方式进行监测,所有请求有IOCP方式处理。

被观察文件的结构定义:

typedef struct directory_info

{

       HANDLE    hDir;

       CHAR          szDirName[260];

       CHAR          szBuffer[4096];

       DWORD      dwBufLength;

       OVERLAPPED Overlapped;  // 此处需要定义overlapp结构

}DIRECTORY_INFO, *LPDIRECTORY_INFO;

#define DIRECTORY_PATH      L"C://TestFolder"

 

实现观察的具体类定义:

 

class cFileUpdateChecker

{

public:

cFileUpdateChecker():hThread(NULL), dwThread(0), hComp(NULL), pdir(NULL)     {}

       ~cFileUpdateChecker()

       {

              if (hThread)         CloseHandle(hThread);    

              if (hComp)          CloseHandle(hComp);     

              if (pdir)

              {

                     PostQueuedCompletionStatus(hComp, 0, NULL, NULL);

                     CloseHandle(pdir->hDir);

                     HeapFree(GetProcessHeap(), 0, pdir);

              }

       }

 

       // 定义IOCP工作线程

       static DWORD WINAPI  ThreadFunc(void* p)

       {

              cFileUpdateChecker* pHost  = (cFileUpdateChecker*)p;

 

              LPDIRECTORY_INFO lpdir = NULL;

              DWORD nbytes;

              LPOVERLAPPED lpOverlapped = NULL;

              PFILE_NOTIFY_INFORMATION fni = NULL;

              DWORD wait = 1000;

             

              while (true)

              {

BOOL bRet = GetQueuedCompletionStatus(pHost->hComp, &nbytes, (PULONG_PTR)&lpdir, &lpOverlapped, wait);

                     if ( FALSE == bRet && NULL == lpOverlapped

&& NULL != pHost->hComp )

                     {

                            wait = INFINITE;

                            continue;

                     }

                     else

                     {

                            if (lpdir)

                            {

                                   fni = (PFILE_NOTIFY_INFORMATION)lpdir->szBuffer;

 

                                   switch(fni->Action)

                                   {

                                   case FILE_ACTION_ADDED:

//The file was added to the directory.

                                          break;

                                   case FILE_ACTION_REMOVED:

//The file was removed from the directory.

                                          break;

                                   case FILE_ACTION_MODIFIED:

//The file was modified. This can be a change in the time stamp or attributes.

                                          break;

                                   case FILE_ACTION_RENAMED_OLD_NAME:

//The file was renamed and this is the old name.

                                          break;

                                   case FILE_ACTION_RENAMED_NEW_NAME:

//The file was renamed and this is the new name.

                                          break;

                                   default:

                                          break;

                                   }

                           

ZeroMemory(&(pHost->pdir->Overlapped), sizeof(OVERLAPPED));

                                   ZeroMemory(pHost->pdir->szBuffer, 4096);

                                   ZeroMemory(pHost->pdir->szDirName, 260);

 

                                   ReadDirectoryChangesW(pHost->pdir->hDir,

                                          pHost->pdir->szBuffer,

                                          sizeof(pHost->pdir->szBuffer),

                                          TRUE,

                                          FILE_NOTIFY_CHANGE_FILE_NAME |

                                          FILE_NOTIFY_CHANGE_DIR_NAME |

                                          FILE_NOTIFY_CHANGE_ATTRIBUTES |

                                          FILE_NOTIFY_CHANGE_SIZE |

                                          FILE_NOTIFY_CHANGE_LAST_ACCESS |

                                          FILE_NOTIFY_CHANGE_CREATION |

                                          FILE_NOTIFY_CHANGE_SECURITY |

                                          FILE_NOTIFY_CHANGE_LAST_WRITE,

                                          &(pHost->pdir->dwBufLength),

                                          (OVERLAPPED*)(&(pHost->pdir->Overlapped)),

                                          NULL

                                          );

                            }

                     }

              }

 

              return 0;

       }

      

 

       bool StartChecker()

       {

hComp = CreateIoCompletionPort(INVALID_HANDLE_VALUE,

NULL, 0, 0);

 

pdir = (LPDIRECTORY_INFO)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DIRECTORY_INFO));

              if (NULL == pdir)

              {

                     return false;

              }

 

              pdir->hDir = CreateFile(DIRECTORY_PATH,

                                                        FILE_LIST_DIRECTORY,

FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,

                                          NULL,

                                          OPEN_EXISTING,

FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED,

                                          NULL);

              if (pdir->hDir == INVALID_HANDLE_VALUE)

              {

                     return false;

              }

 

              // 启动工作线程

              hThread = CreateThread(NULL, 0, ThreadFunc, this,0, &dwThread);

              if (NULL == hThread)

              {

                     return false;

              }

      

// 此处投递IO请求的时候必须清零,开始因为没有清零总是收不到完成事件

ZeroMemory(&(pdir->Overlapped), sizeof(OVERLAPPED));

              ZeroMemory(pdir->szBuffer, 4096);

              ZeroMemory(pdir->szDirName, MAX_PATH);

 

              // 投递I/O请求到完成端口

HANDLE hRet = CreateIoCompletionPort(pdir->hDir, hComp, (ULONG_PTR)pdir, 0);

              if (NULL == hComp)

              {

                     return false;

              }

 

              BOOL bRet = ReadDirectoryChangesW(pdir->hDir,

                     pdir->szBuffer,

                     4096,

                     TRUE,

                     FILE_NOTIFY_CHANGE_FILE_NAME |

                     FILE_NOTIFY_CHANGE_DIR_NAME |

                     FILE_NOTIFY_CHANGE_ATTRIBUTES |

                     FILE_NOTIFY_CHANGE_SIZE |

                     FILE_NOTIFY_CHANGE_LAST_ACCESS |

                     FILE_NOTIFY_CHANGE_CREATION |

                     FILE_NOTIFY_CHANGE_SECURITY |

                     FILE_NOTIFY_CHANGE_LAST_WRITE,

                     &pdir->dwBufLength,

                     &(pdir->Overlapped),

                     NULL

                     );

 

              if (FALSE == bRet)

              {

                     return false;

              }

              return true;

       }

 

             

private:

       HANDLE hThread;

       DWORD dwThread;

       HANDLE  hComp;

       LPDIRECTORY_INFO pdir;

};

 

参考资料

1. MSDN 网站 - http://msdn.microsoft.com/en-us/library/aa365198%28VS.85%29.aspx

 

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值