现在的位置: 首页 > 综合 > 正文

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

2013年12月03日 ⁄ 综合 ⁄ 共 4299字 ⁄ 字号 评论关闭

作者: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 |

                       

抱歉!评论已关闭.