首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> 關於VC++

多執行緒檔案搜尋類 CRapidFinder:高效能平行掃描實作

     編輯:關於VC++

Windows 內建搜尋採循序掃描,面對深層目錄結構效率低落。本文實作一個採用多執行緒平行搜尋的 MFC 類別 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();   // 重置

執行緒通訊:自訂訊息機制

每個工作執行緒透過 PostMessage 向 UI 執行緒發送自訂訊息,回報進度與結果:

訊息用途WPARAMLPARAM
WM_THREADEXIT執行緒結束結束代碼-
WM_THREADCOUNT活動執行緒數執行緒數-
WM_FINDERITEM搜尋結果結果字串指標檔案屬性
WM_THREADPAUSE程式暫停通知--
WM_FINDERFOLDER目前掃描目錄目錄字串指標-

演算法核心:生產者-消費者模式 + 臨界區同步

共享資源 CStringList m_DirList 作為「待掃描目錄佇列」:

  • 各執行緒從佇列頭取出目錄掃描(消費者)
  • 掃描到子目錄時加入佇列尾(生產者)
  • 檔案則直接比對,符合條件發送 WM_FINDERITEM
  • 存取佇列時以 Critical Section 保護,確保執行緒安全

結束條件判斷:雙重檢查機制

單純檢查佇列為空不足夠,因為活動執行緒可能正在產生新目錄。真正結束條件:

m_DirList.IsEmpty() && m_ActiveCount == 0

其中 m_ActiveCount 以 InterlockedIncrement/Decrement 維護,記錄「正在掃描中」的執行緒數。

核心執行緒函式 ThreadProc 精簡邏輯

DWORD WINAPI CRapidFinder::ThreadProc(LPVOID lpParam) {
    CRapidFinder* finder = (CRapidFinder*)lpParam;
    CFileFind filefinder;
    CStringList filelist;
    CString PathStr, CurPath;
    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, finder->m_ActiveCount, 0);
            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, finder->m_ActiveCount, 0);
        } else if (!bNewActive) continue;

        // 通知 UI 目前掃描目錄
        SendMessage(finder->m_MainhWnd, WM_FINDERFOLDER, (WPARAM)lpFolder, 0);

        // 掃描檔案與目錄
        if (filefinder.FindFile(CurPath)) {
            do {
                if (!filefinder.FindNextFile()) break;
                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 (true);
        }

        // 比對檔案並回報結果
        while (!filelist.IsEmpty()) {
            PathStr = filelist.RemoveHead();
            if (finder->MatchProc(PathStr))
                SendMessage(finder->m_MainhWnd, WM_FINDERITEM, (WPARAM)&PathStr, 0);
        }
    }

    delete lpFolder;
    filefinder.Close();
    return 0;
}

效能測試與經驗值

  • 純檔名搜尋:速度略快於 Windows 內建搜尋(Win9x/2000 環境測試)
  • 最佳執行緒數:5~10 條時效能最佳
  • 過多執行緒反而變慢:超過 50 條時,CPU 大部分時間花在 Context Switch,且多數執行緒處於等待狀態
  • 內容搜尋(KMP 演算法):仍慢於 Windows 內建,歡迎高手指教優化方向

編譯環境

  • VC++ 6.0 / Windows 2000
  • 原始碼已附上,歡迎參考改進

這是一個多執行緒應用的入門範例,不當之處請各位前輩指正。聯繫信箱:jruv@163.com

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved