程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> VC >> 關於VC++ >> 用多線程實現文件查找的例子

用多線程實現文件查找的例子

編輯:關於VC++

本程序用多線程的思想實現了一個文件查找類CRapidFinder,以加速文件的查找,運行效果圖如下:

其中成員函數:

//設置程序主窗口句柄,要匹配的文件名,路徑名
void FinderSet(HWND MainHwnd,CString MatchName="*.*",CString MatchDir="");
//設置線程數及優先級
void ThreadSet(LONG MaxThreadCount=5,int priority=0);
//搜索選項
void FinderOption(FINDEROPTION FinderOption);

//查找操作
BOOL StartFinder();    //開始查找
void PauseFinder();    //暫停查找
void ResumeFinder();    //繼續查找
void StopFinder();     //停止查找
void FinderReset();    //查找重置

//搜索選項
void FinderOption(FINDEROPTION FinderOption);

每個線程通過自定義的消息與UI線程通信,反映當前的查找進度與查找結果。

//自定義通知消息==========================================================
//WM_THREADEXIT 主線程結束  WPARAM: 結束碼
//WM_THREADCOUNT 活動線程數目 WPARAM: 線程數
//WM_FINDERITEM 查找結果   WPARAM: 結果字符串地址 LPARAM:文件屬性
//WM_THREADPAUSE 程序暫停
//WM_FINDERFOLDER當前查找目錄 WPARAM: 目錄字符串地址
//==================================================================

可通過ThreadSet()設置線程的數目與優先級,這樣MainThreadProc()中就會產生相應數目的線程

編程思路:

定義一個臨時目錄列表CStringList m_DirList; 線程每找到一個目錄就將它放在m_DirList尾,若找到的是文件,就用MatchProc()進行比較,判斷是否符合查找條件。若符合就向UI線程發送消息WM_FINDERITEM,以進行界面顯示。然後,線程繼續在當前目錄中查找直到當前目錄全部查找完畢。再從m_DirList隊頭取一個新的目錄進行查找。

這裡有一個要注意的地方就是m_DirList為每個線程所共有的資源,所以在訪問m_DirList時要注意一下線程間的互斥,這可以用臨界區操作來保證。

那麼,如何來判斷文件查找應該結束了呢?僅判斷m_DirList為空是不夠的,因為當m_DirList為空時,有可能還有活動的線程,這些活動的線程可能還會產生新的未查找的目錄,故只有在m_DirList為空且當前的活動線程數為0時才可以斷定查找結束。(這裡的"活動線程"指正在進行查找操作的線程,"非活動線程"指處於等待新的待查目錄狀態的線程)

這部分在線程函數中實現:

DWORD WINAPI CRapidFinder::ThreadProc(LPVOID lpParam)
{
  CRapidFinder *finder=(CRapidFinder *)lpParam;
  CFileFind filefinder;
  CStringList filelist;
  CString PathStr;
  CString CurPath;
  int re;
  BYTE bNewActive=1,bOldActive;
  CString *lpFolder=new CString;
  while(1)
  {
    bOldActive=bNewActive;
    if(WaitForSingleObject(finder->m_hExitEvent,0)!=WAIT_TIMEOUT)
    {
      if(bOldActive)InterlockedDecrement(&finder->m_ActiveCount);
      PostMessage(finder->m_MainhWnd,WM_THREADCOUNT,(WPARAM)finder->m_ActiveCount,NULL);
      break;
    }

    if(!finder->m_ActiveCount)
    {
      SetEvent(finder->m_hExitEvent);
      finder->m_ExitCode=finder->EXIT;
      break;
    }
     //進入臨界區
    EnterCriticalSection(&finder->m_gCriticalSection);
    if(finder->m_DirList.IsEmpty())bNewActive=0;
    else
    {
       bNewActive=1;
      *lpFolder=finder->m_DirList.RemoveHead();
       CurPath=*lpFolder+_T("\\*.*");
    }
    LeaveCriticalSection(&finder->m_gCriticalSection);
    //離開臨界區

   if(bNewActive!=bOldActive)
   {
     bNewActive?InterlockedIncrement(&finder->m_ActiveCount):InterlockedDecrement(&finder->m_ActiveCount);
     PostMessage(finder->m_MainhWnd,WM_THREADCOUNT,(WPARAM)finder->m_ActiveCount,NULL);
   }
   else if(!bNewActive) continue;

   SendMessage(finder->m_MainhWnd,WM_FINDERFOLDER,(WPARAM)lpFolder,NULL);
    if(filefinder.FindFile(LPCTSTR(CurPath)))
    {
      do
      {
        re=filefinder.FindNextFile();
        if(filefinder.IsDots())continue;
        PathStr=filefinder.GetFilePath();
        if(filefinder.IsDirectory())
        {
          EnterCriticalSection(&finder->m_gCriticalSection);
          finder->m_DirList.AddTail(PathStr);
          LeaveCriticalSection(&finder->m_gCriticalSection);
        }
        else filelist.AddTail(PathStr);
      }while(re);
    }
    while(!filelist.IsEmpty())
    {
      PathStr=filelist.RemoveHead();
      if(finder->MatchProc(PathStr))
        SendMessage(finder->m_MainhWnd,WM_FINDERITEM,(WPARAM)&PathStr,NULL);
    }
  }
delete lpFolder;
filefinder.Close();
return 0;
}

程序編譯運行後,僅進行文件名查找時經測試速度比Windows自帶的查找程序稍快(Win9x的查找程序是獨立的,而Win2000下是集成在Explorer中的),當線程數在5-10之間時速度最快,而超過50時速度反而變慢,這就說明了並不是線程越多越好。線程數過多,CPU的大部分開銷花在線程間切換上,而且由於沒有足夠的待查目錄,大多數的線程處在等待狀態,占用了大量的系統資源,從而使速度變慢。

當進行包含文字的查找時,我用的是KMP匹配算法,但是速度還是比Windows自帶查找程序慢,不知它的原理是什麼,還希望知道的朋友告知!

本例只是多線程應用的一個極簡單的例子,未免贻笑大方,筆者接觸多線程編程時間不長,其中的不妥之處,還請大家指正,歡迎與我聯系:[email protected]

程序在Win2000,VC++6.0通過。

本文配套源碼

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved