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

VC++ 多執行緒實現高速檔案搜尋

     編輯:關於VC++

前言

Windows 檔案搜尋預設為單執行緒遞迴掃描,效率低且程式碼繁瑣 (需手動遞迴目錄樹)。本文提出 **多執行緒同步搜尋** 策略:發現子目錄即建立新執行緒處理,檔案在執行緒內即時比對,實現寬度優先並行掃描,代碼極簡且效能大幅提升。

核心 API

  • FindFirstFile / FindNextFile:Win32 列舉目錄項目
  • AfxBeginThread:MFC 執行緒建立
  • CMutex / CEvent:同步物件保護共享資料

資料結構


// 執行緒參數
struct THREADPARAM {
    CString strPath;    // 待掃描目錄
    CString strFileName;// 目標檔名
};
THREADPARAM g_param;

// 同步物件
CMutex g_mutexThreadCount, g_mutexThreadParam, g_mutexPath;
CEvent g_event(FALSE, FALSE); // 手動重設, 初始無訊號

// 全域狀態
UINT g_uThreadCount = 0;
CStringArray g_strPathArray; // 找到的完整路徑

執行緒函式


UINT GetFilePathThreadProc(LPVOID pParam)
{
    if (!pParam) return 0;
    THREADPARAM* p = (THREADPARAM*)pParam;
    CString strPath = p->strPath;
    CString strTarget = p->strFileName;

    // 計數器 +1
    g_mutexThreadCount.Lock(); g_uThreadCount++; g_mutexThreadCount.Unlock();

    WIN32_FIND_DATA* pInfo = new WIN32_FIND_DATA;
    HANDLE hFind = ::FindFirstFile(strPath + _T("\\*.*"), pInfo);
    if (hFind == INVALID_HANDLE_VALUE) {
        delete pInfo;
        g_mutexThreadCount.Lock();
        if (--g_uThreadCount == 0) g_event.SetEvent();
        g_mutexThreadCount.Unlock();
        return 0;
    }

    do {
        // 跳過 . 和 ..
        if (pInfo->cFileName[0] == '.') continue;

        CString name = pInfo->cFileName;

        if (pInfo->dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
            // 子目錄 → 建立新執行緒遞迴掃描
            g_mutexThreadParam.Lock();
            g_param.strPath = strPath + _T("\\") + name;
            g_param.strFileName = strTarget;
            AfxBeginThread(GetFilePathThreadProc, &g_param, THREAD_PRIORITY_NORMAL);
            g_mutexThreadParam.Unlock();
        }
        else {
            // 檔案 → 比對名稱
            if (name == strTarget) {
                g_mutexPath.Lock();
                g_strPathArray.Add(strPath + _T("\\") + name);
                g_mutexPath.Unlock();
                // 找到即可結束此執行緒 (若只找第一個)
                g_mutexThreadCount.Lock();
                if (--g_uThreadCount == 0) g_event.SetEvent();
                g_mutexThreadCount.Unlock();
                delete pInfo;
                return 0;
            }
        }
    } while (::FindNextFile(hFind, pInfo));

    ::FindClose(hFind);
    delete pInfo;

    g_mutexThreadCount.Lock();
    if (--g_uThreadCount == 0) g_event.SetEvent();
    g_mutexThreadCount.Unlock();
    return 0;
}

主控流程


void GetFilePath()
{
    g_event.ResetEvent();
    g_uThreadCount = 0;
    g_strPathArray.RemoveAll();

    g_param.strPath = m_strStartPath;   // 使用者輸入起始目錄
    g_param.strFileName = m_strTargetFile; // 使用者輸入檔名

    AfxBeginThread(GetFilePathThreadProc, &g_param, THREAD_PRIORITY_NORMAL);

    // 等待所有執行緒完成
    ::WaitForSingleObject(g_event.m_hObject, INFINITE);

    if (g_strPathArray.GetSize() == 0)
        AfxMessageBox(_T("未找到檔案"));
    else
        for (int i = 0; i < g_strPathArray.GetSize(); ++i)
            AfxMessageBox(g_strPathArray[i]);
}

中途取消搜尋

維護一個 CArray 記錄所有啟動的執行緒指標:


// 啟動時
CWinThread* pThread = AfxBeginThread(...);
g_threadArray.Add(pThread);

// 取消時
for (int i = 0; i < g_threadArray.GetSize(); ++i) {
    DWORD exitCode;
    if (::GetExitCodeThread(g_threadArray[i]->m_hThread, &exitCode) &&
        exitCode == STILL_ACTIVE)
        ::TerminateThread(g_threadArray[i]->m_hThread, 0);
}
g_threadArray.RemoveAll();
g_event.SetEvent(); // 解除主執行緒等待

效能與適用性分析

指標單執行緒遞迴多執行緒寬度優先
程式碼複雜度高 (手動堆疊/遞迴)低 (系統自動排程)
CPU 利用率單核心多核心並行 (I/O 密集型顯著受益)
記憶體開銷低較高 (每執行緒 1MB 堆疊 + 核心物件)
深度目錄風險堆疊溢位無 (各目錄獨立執行緒)
檔案系統壓力循序讀取並發隨機讀取 (SSD 受益大, HDD 可能降速)

改進建議

  • 執行緒池:限制最大並發數 (如 64),避免爆炸性建立執行緒導致系統卡頓。
  • I/O 完成埠 (IOCP):配合 FindFirstFileEx(FindExInfoBasic, FIND_FIRST_EX_LARGE_FETCH) 非同步列舉,單執行緒即可高效處理百萬檔案。
  • 索引搜尋:Windows Search / Everything SDK / 自建倒排索引,毫秒級回應。
  • Unicode/長路徑:使用 \\?\ 前綴支援 >260 字元路徑。

編譯環境:VC++6.0 / Windows 2000 測試通過。現代專案建議配合 C++17 std::filesystem + 執行緒池重寫。

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