zoukankan      html  css  js  c++  java
  • 使用完成端口监控文件目录的例子

    和完成例程比较。完成端口的效率更高。其主要原因是完成端口可以指定线程池。这么说吧,完成例程,每次只能由一个线程来监控IO 完成变化。但是完成端口,却可以指定

    一堆线程(想象一下一个人干活和一群人干活的区别)轮班的监控,即1号线程忙碌了,2号线程顶上去,如果2号也忙,3号顶上去!这样,效率大大提高。

    但是呢,线程的创建和销毁是非常消耗时间的。所以,使用了线程池。另外线程涉及到CPU 上下文的切换问题。所以多线程的数量一般选择2*CPU数量,但这是个经验值

    实际情况需要反复测试。

    下面是BCB实现效果及源码(参考资料 windows 核心编程 第10章,11章)

    2014/12/23更新,增加临界值保证cout的输出不出现乱码

    2014/12/23更新,将ReadDirectoryChangesW 的缓冲区,移动到多线程中执行。

      1 //---------------------------------------------------------------------------
      2 
      3 #include <vcl.h>
      4 #include <iostream>
      5 using namespace std;
      6 #pragma hdrstop
      7 
      8 //---------------------------------------------------------------------------
      9 
     10 #pragma argsused
     11 
     12 HANDLE hMonitorDir = NULL;
     13 HANDLE hCompletePort = NULL;
     14 //因为cout 不是线程安全的,所以要用临界值
     15 CRITICAL_SECTION cs;
     16 const DWORD CompleteKey = 1;
     17 //让完成端口处理线程池自己决定最多的线程并发数
     18 const DWORD MaxThreadCount = 0;
     19 DWORD dwByteReturn;
     20 OVERLAPPED overlapped={0};
     21 DWORD dwError = 0;
     22 int fileCount = 0;
     23 
     24 
     25 //线程池
     26 DWORD WINAPI ThreadProc(LPVOID lpParameter)
     27 {
     28     DWORD dwTranferBytes = 0;
     29     DWORD dwKey = 0;
     30     LPOVERLAPPED pOverLapped = &overlapped;
     31     //捕获文件信息的缓冲长度
     32     DWORD dwBufLen
     33         =2*(sizeof(FILE_NOTIFY_INFORMATION)+MAX_PATH*sizeof(TCHAR));
     34     //捕获文件信息的缓冲buffer
     35     FILE_NOTIFY_INFORMATION* Buffer
     36         =(FILE_NOTIFY_INFORMATION*)HeapAlloc(GetProcessHeap(),HEAP_ZERO_MEMORY,dwBufLen);
     37 
     38     //开始监控文件夹
     39     if(!ReadDirectoryChangesW(hMonitorDir,Buffer,dwBufLen,TRUE,
     40             FILE_NOTIFY_CHANGE_DIR_NAME|FILE_NOTIFY_CHANGE_FILE_NAME,
     41             &dwByteReturn,&overlapped,NULL))
     42     {
     43         dwError = GetLastError();
     44         CloseHandle(hMonitorDir);
     45         HeapFree(GetProcessHeap(),0,Buffer);
     46         cout<<"监控文件夹失败! "<<SysErrorMessage(dwError).c_str()<<endl;
     47         return 0;
     48     }
     49     
     50     while(true)
     51     {
     52 
     53         //完成端口的关键所在
     54         //和完成例程相比,完成端口的优势是可以用线程池来监控IO,效率更高
     55         BOOL blOk = GetQueuedCompletionStatus(hCompletePort,
     56                                 &dwTranferBytes,
     57                                 &dwKey,
     58                                 &pOverLapped,INFINITE);
     59 
     60         dwError = GetLastError();
     61 
     62         if(blOk && CompleteKey == dwKey)
     63         {
     64             //输出线程编号
     65             EnterCriticalSection( &cs );
     66             cout<<"线程号:"<<GetCurrentThreadId()<<endl;
     67             LeaveCriticalSection( &cs );
     68             
     69             //捕获到文件变化
     70             FILE_NOTIFY_INFORMATION* notify = Buffer;
     71 
     72             AnsiString fileName =
     73                     WideCharLenToString(
     74                         notify->FileName,notify->FileNameLength/2);
     75             do
     76             {
     77                 bool blNormal = true;
     78                 switch(notify->Action)
     79                 {
     80                 case FILE_ACTION_ADDED:
     81                     {
     82                         EnterCriticalSection( &cs );
     83                         cout<<"增加了文件"<<fileName.c_str()<<endl;
     84                         LeaveCriticalSection( &cs );
     85                     }
     86                     break;
     87                 case FILE_ACTION_REMOVED:
     88                     {
     89                         EnterCriticalSection( &cs );
     90                         cout<<"删除了文件"<<fileName.c_str()<<endl;
     91                         LeaveCriticalSection( &cs );
     92                     }
     93                     break;
     94                 case FILE_ACTION_MODIFIED:
     95                     {
     96                         EnterCriticalSection( &cs );
     97                         cout<<"修改了文件"<<fileName.c_str()<<endl;
     98                         LeaveCriticalSection( &cs );
     99                     }
    100                     break;
    101                 case FILE_ACTION_RENAMED_OLD_NAME:
    102                     {
    103                         EnterCriticalSection( &cs );
    104                         cout<<"被重名的文件"<<fileName.c_str()<<endl;
    105                         LeaveCriticalSection( &cs );
    106                     }
    107                     break;
    108                 case FILE_ACTION_RENAMED_NEW_NAME:
    109                     {
    110                         EnterCriticalSection( &cs );
    111                         cout<<"新命名的文件"<<fileName.c_str()<<endl;
    112                         LeaveCriticalSection( &cs );
    113                     }
    114                     break;
    115                 default:   //有可能已经溢出了!
    116                     blNormal = false;
    117                     break;
    118                 }
    119 
    120                 if(!blNormal)
    121                 {
    122                     break;
    123                 }
    124                 //将指针偏移offset个字节
    125                 notify =  notify + notify->NextEntryOffset;
    126             }
    127             while(notify->NextEntryOffset>0);
    128 
    129             if(!ReadDirectoryChangesW(hMonitorDir,Buffer,dwBufLen,TRUE,
    130                     FILE_NOTIFY_CHANGE_DIR_NAME|FILE_NOTIFY_CHANGE_FILE_NAME ,
    131                     &dwByteReturn,&overlapped,NULL))
    132             {
    133                 dwError = GetLastError();
    134                 CloseHandle(hMonitorDir);
    135                 CloseHandle(hCompletePort);
    136                 HeapFree(GetProcessHeap(),0,Buffer);
    137                 cout<<"监控文件夹失败! "<<SysErrorMessage(dwError).c_str()<<endl;
    138                 break;
    139             }
    140         }
    141         else
    142         {
    143             cout<<"完成端口异常! "<<SysErrorMessage(dwError).c_str()<<endl;
    144             CloseHandle(hMonitorDir);
    145             CloseHandle(hCompletePort);
    146             HeapFree(GetProcessHeap(),0,Buffer);
    147             break;
    148         }
    149     }
    150 
    151     return 0;
    152 }
    153 
    154 int main(int argc, char* argv[])
    155 {
    156     cout<<"开始监控程序目录!...."<<endl;
    157     AnsiString fileName = ExtractFileDir(Application->ExeName);
    158 
    159     //打开目录
    160     hMonitorDir=CreateFile(fileName.c_str(),
    161         FILE_LIST_DIRECTORY,  //表明打开一个目录
    162         FILE_SHARE_DELETE|FILE_SHARE_READ|FILE_SHARE_WRITE,
    163         NULL,
    164         OPEN_EXISTING,
    165         FILE_FLAG_BACKUP_SEMANTICS|FILE_FLAG_OVERLAPPED,//FILE_FLAG_OVERLAPPED表示异步模式
    166         NULL);
    167     dwError = GetLastError();
    168     if (INVALID_HANDLE_VALUE == hMonitorDir)
    169     {
    170         cout<<"打开文件目录失败! "<<SysErrorMessage(dwError).c_str()<<endl;
    171         return 0;
    172     }
    173     //创建完成端口
    174     hCompletePort =
    175         CreateIoCompletionPort(hMonitorDir,NULL,CompleteKey,MaxThreadCount);
    176     dwError = GetLastError();
    177     if(NULL == hCompletePort)
    178     {
    179         cout<<"创建完成端口失败! "<<SysErrorMessage(dwError).c_str()<<endl;
    180         CloseHandle(hMonitorDir);
    181         return 0;
    182     }
    183 
    184     InitializeCriticalSection( &cs );
    185     //启动线程池,在线程池中进行IO 完成监控
    186     //如果是VISTA 以上级别的操作系统,建议使用
    187     //TrySubmitThreadpoolCallback
    188     //这里,我启用五个工作线程,但实际上完成端口会自己调剂
    189     for(int i = 0; i<5; i++)
    190     {
    191         QueueUserWorkItem(ThreadProc,NULL,0x00000000|0x00000010);
    192     }
    193 
    194 
    195 
    196     int i = 0;
    197     cin>>i;
    198     CloseHandle(hMonitorDir);
    199     CloseHandle(hCompletePort);
    200     return 0;
    201 }
    202 //---------------------------------------------------------------------------
  • 相关阅读:
    bzoj1015星球大战(并查集+离线)
    bzoj1085骑士精神(搜索)
    bzoj1051受欢迎的牛(Tarjan)
    左偏树学习
    hdu1512 Monkey King(并查集,左偏堆)
    左偏树(模板)
    PAT (Basic Level) Practice (中文) 1079 延迟的回文数 (20分) (大数加法)
    PAT (Basic Level) Practice (中文) 1078 字符串压缩与解压 (20分) (字符转数字——栈存放)
    PAT (Basic Level) Practice (中文) 1077 互评成绩计算 (20分) (四舍五入保留整数)
    PAT (Basic Level) Practice (中文) 1076 Wifi密码 (15分)
  • 原文地址:https://www.cnblogs.com/songr/p/4179298.html
Copyright © 2011-2022 走看看