C++实现多线程查找文件实例

主要是多线程的互斥 文件 的查找
多线程互斥的框架

//线程函数  

UINT FinderEntry(LPVOID lpParam)  

{  

    //CRapidFinder通过参数传递进来   

    CRapidFinder* pFinder = (CRapidFinder*)lpParam;  

    CDirectoryNode* pNode = NULL;  

    BOOL bActive = TRUE; //bActive为TRUE,表示当前线程激活  

    //循环处理m_listDir列表中的目录  

    while (1)  

    {  

        //从列表中取出一个目录  

        ::EnterCriticalSection(&pFinder->m_cs);  

        if (pFinder->m_listDir.IsEmpty()) //目录列表为空,当前线程不激活,所以bAactive=FALSE  

        {  

            bActive = FALSE;  

        }  

        else  

        {  

            pNode = pFinder->m_listDir.GetHead(); //得到一个目录  

            pFinder->m_listDir.Remove(pNode);    //从目录列表中移除  

        }  

        ::LeaveCriticalSection(&pFinder->m_cs);  

        //如果停止当前线程  

        if (bActive == FALSE)  

        {  

            //停止当前线程  

            //线程数--  

            pFinder->m_nThreadCount--;  

              

            //如果当前活动线程数为0,跳出,结束  

            if (pFinder->m_nThreadCount == 0)  

            {  

                ::LeaveCriticalSection(&pFinder->m_cs);  

                break;  

            }  

            ::LeaveCriticalSection(&pFinder->m_cs);  

            //当前活动线程数不为0,等待其他线程向目录列表中加目录  

            ::ResetEvent(pFinder->m_hDirEvent);  

            ::WaitForSingleObject(pFinder->m_hDirEvent, INFINITE);  

  

            //运行到这,就说明其他线程唤醒了本线程  

              

            pFinder->m_nThreadCount++; //激活了自己的线程,线程数++  

              

            bActive = TRUE; //当前线程活了  

            continue; //跳到while,  

        }  

        //从目录列表中成功取得了目录  

<span style="white-space:pre">      </span>......................  

          

        //if (pNode)  

        //{  

        //  delete pNode;  

        //  pNode = NULL;  

        //}  

  

  

    }//end while  

  

    //促使一个搜索线程从WaitForSingleObject返回,并退出循环  

    ::SetEvent(pFinder->m_hDirEvent);  

  

    //判断此线程是否是最后一个结束循环的线程,如果是就通知主线程  

    if (::WaitForSingleObject(pFinder->m_hDirEvent,0) != WAIT_TIMEOUT)  

    {  

        ::SetEvent(pFinder->m_hExitEvent);  

    }  

    return 1;  

}
 

查找文件 的框架:

//从目录列表中成功取得了目录  

WIN32_FIND_DATA fileData;  

HANDLE hFindFile;  

//生成正确的查找字符串  

if (pNode->szDir[strlen(pNode->szDir)-1] != '\\')  

{  

    strcat(pNode->szDir,"\\");  

}  

strcat(pNode->szDir, "*.*");  

//查找文件的框架  

hFindFile = ::FindFirstFile(pNode->szDir, &fileData);  

if (hFindFile != INVALID_HANDLE_VALUE )  

{  

    do   

    {  

 //如果是当前目录,跳过  

 if (fileData.cFileName[0] == '.')  

 {  

     continue;  

 }  

 //如果是目录  

 if (fileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)  

 {  

     //将当前目录加入到目录列表  

     。。。。。。  

     //使一个线程从非活动状态变成活动状态  

     ::SetEvent(pFinder->m_hDirEvent);  

 }  

 else //如果是文件  

 {  

     。。。。。。。。。。。。。  

 }  

    } while (::FindNextFile(hFindFile, &fileData));  

}
 

所有代码main.cpp:

#include "RapidFinder.h"  

#include <stddef.h>  

#include <stdio.h>  

#include <process.h>  

  

//m_nMaxThread 是const int类型,只能通过这种方式初始化  

CRapidFinder::CRapidFinder(int nMaxThread):m_nMaxThread(nMaxThread)  

{  

    m_nResultCount = 0;  

    m_nThreadCount = 0;  

    m_listDir.Construct(offsetof(CDirectoryNode, pNext));  //offsetof在stddef.h头文件中  

    ::InitializeCriticalSection(&m_cs);  

    m_szMatchName[0] = '\0';  

    m_hDirEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL);  

    m_hExitEvent = ::CreateEvent(NULL, FALSE, FALSE, NULL);  

  

}  

  

CRapidFinder::~CRapidFinder()  

{  

    ::DeleteCriticalSection(&m_cs);  

    ::CloseHandle(m_hDirEvent);  

    ::CloseHandle(m_hExitEvent);  

}  

  

BOOL    CRapidFinder::CheckFile(LPCTSTR lpszFileName)  

{  

    //定义两个字符串  

    char string[MAX_PATH];  

    char strSearch[MAX_PATH];  

    strcpy(string, lpszFileName);  

    strcpy(strSearch, m_szMatchName);  

  

    //将字符串大写  

    _strupr(string);  

    _strupr(strSearch);  

  

    //比较string中是否含有strSearch  

    if (strstr(string, strSearch) != NULL)  

    {  

        return TRUE;  

    }  

    return FALSE;  

}

  

//线程函数  

UINT FinderEntry(LPVOID lpParam)  

{  

    //CRapidFinder通过参数传递进来   

    CRapidFinder* pFinder = (CRapidFinder*)lpParam;  

    CDirectoryNode* pNode = NULL;  

    BOOL bActive = TRUE; //bActive为TRUE,表示当前线程激活  

    //循环处理m_listDir列表中的目录  

    while (1)  

    {  

        //从列表中取出一个目录  

        ::EnterCriticalSection(&pFinder->m_cs);  

        if (pFinder->m_listDir.IsEmpty()) //目录列表为空,当前线程不激活,所以bAactive=FALSE  

        {  

            bActive = FALSE;  

        }  

        else  

        {  

            pNode = pFinder->m_listDir.GetHead(); //得到一个目录  

            pFinder->m_listDir.Remove(pNode);    //从目录列表中移除  

        }  

        ::LeaveCriticalSection(&pFinder->m_cs);  

        //如果停止当前线程  

        if (bActive == FALSE)  

        {  

            //停止当前线程  

            ::EnterCriticalSection(&pFinder->m_cs);  

            pFinder->m_nThreadCount--;  

              

            //如果当前活动线程数为0,跳出,结束  

            if (pFinder->m_nThreadCount == 0)  

            {  

                ::LeaveCriticalSection(&pFinder->m_cs);  

                break;  

            }  

            ::LeaveCriticalSection(&pFinder->m_cs);  

            //当前活动线程数不为0,等待其他线程向目录列表中加目录  

            ::ResetEvent(pFinder->m_hDirEvent);  

            ::WaitForSingleObject(pFinder->m_hDirEvent, INFINITE);  

  

            //运行到这,就说明其他线程向目录列表中加入了新的目录  

            ::EnterCriticalSection(&pFinder->m_cs);  

            pFinder->m_nThreadCount++; //激活了自己的线程,线程数++  

            ::LeaveCriticalSection(&pFinder->m_cs);  

            bActive = TRUE; //目录不再为空  

            continue; //跳到while,重新在目录列表中取目录  

        }  

        //从目录列表中成功取得了目录  

        WIN32_FIND_DATA fileData;  

        HANDLE hFindFile;  

        //生成正确的查找字符串  

        if (pNode->szDir[strlen(pNode->szDir)-1] != '\\')  

        {  

            strcat(pNode->szDir,"\\");  

        }  

        strcat(pNode->szDir, "*.*");  

        //查找文件的框架  

        hFindFile = ::FindFirstFile(pNode->szDir, &fileData);  

        if (hFindFile != INVALID_HANDLE_VALUE )  

        {  

            do   

            {  

                //如果是当前目录,跳过  

                if (fileData.cFileName[0] == '.')  

                {  

                    continue;  

                }  

                //如果是目录  

                if (fileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)  

                {  

                    //将当前目录加入到目录列表  

                    CDirectoryNode* p = new CDirectoryNode;  

                    strncpy(p->szDir, pNode->szDir, strlen(pNode->szDir)-3); //将pNode后面的*.*三位去掉  

                    strcat(p->szDir, fileData.cFileName);  

                    ::EnterCriticalSection(&pFinder->m_cs);  

                    pFinder->m_listDir.AddHead(p);  

                    ::LeaveCriticalSection(&pFinder->m_cs);  

  

                    // 现在的p刚加入列表,就要delete,肯定会出错  

                    //delete p;  

                    //p = NULL;  

  

                    //使一个线程从非活动状态变成活动状态  

                    ::SetEvent(pFinder->m_hDirEvent);  

                }  

                else //如果是文件  

                {  

                    //判断是否为要查找的文件   

                    if (pFinder->CheckFile(fileData.cFileName)) //符合查找的文件   

                    {  

                        //打印  

                        ::EnterCriticalSection(&pFinder->m_cs);  

                        pFinder->m_nResultCount++;  

                        ::LeaveCriticalSection(&pFinder->m_cs);  

                        printf("find %d:%s\n", pFinder->m_nResultCount, fileData.cFileName);  

                    }  

                }  

            } while (::FindNextFile(hFindFile, &fileData));  

        }  

        //if (pNode)  

        //{  

        //  delete pNode;  

        //  pNode = NULL;  

        //}  

  

  

    }//end while  

  

    //促使一个搜索线程从WaitForSingleObject返回,并退出循环  

    ::SetEvent(pFinder->m_hDirEvent);  

  

    //判断此线程是否是最后一个结束循环的线程,如果是就通知主线程  

    if (::WaitForSingleObject(pFinder->m_hDirEvent,0) != WAIT_TIMEOUT)  

    {  

        ::SetEvent(pFinder->m_hExitEvent);  

    }  

    return 1;  

}  

  

void    main()  

{  

    printf("start:\n");  

    CRapidFinder* pFinder = new CRapidFinder(64);  

    CDirectoryNode* pNode = new CDirectoryNode;  

    char szPath[] = "c:\\";  

    char szFile[] = "config";  

  

    strcpy(pNode->szDir, szPath);  

    pFinder->m_listDir.AddHead(pNode);  

  

    strcpy(pFinder->m_szMatchName, szFile);  

    pFinder->m_nThreadCount = pFinder->m_nMaxThread;  

    //开始开启多线程  

    for (int i=0;i< pFinder->m_nMaxThread;i++)  

    {  

        ::CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)FinderEntry, pFinder, 0, NULL);  

    }  

  

    //只有m_hExitEvent受信状态,主线程才恢复运行  

    ::WaitForSingleObject(pFinder->m_hExitEvent,INFINITE);  

    printf("共找到%d\n", pFinder->m_nResultCount);  

    //if (pNode != NULL) delete pNode;  

    if (pFinder != NULL) delete pFinder;  

  

    getchar();  

    return;  

}

rapidfinder.h文件如下:

#include "_AFXTLS_.H"  

  

struct CDirectoryNode: public CNoTrackObject  

{  

    CDirectoryNode* pNext;  

    char szDir[MAX_PATH];  

};  

  

class CRapidFinder  

{  

public:  

    CRapidFinder(int nMaxThread); //构造函数  

    virtual ~CRapidFinder();    //析构函数  

    BOOL    CheckFile(LPCTSTR lpszFileName); //检查lpszFileName是否符合查找条件  

    int     m_nResultCount; //找到的结果数量  

    int     m_nThreadCount; //当前的线程数量  

    CTypedSimpleList<CDirectoryNode*> m_listDir; //查找目录  

    CRITICAL_SECTION    m_cs;   //共享  

    const int   m_nMaxThread;   //最大线程数量  

    char    m_szMatchName[MAX_PATH]; //要查找的名称  

    HANDLE  m_hDirEvent;    //添加新目录后置位  

    HANDLE  m_hExitEvent;   //所有线程退出时置位  

};
 


下面这两个类就是实现了simplelist类和模板
_afxatl.cpp文件:

#include "_AFXTLS_.H"  

  

void CSimpleList::AddHead(void* p)  

{  

    *GetNextPtr(p) = m_pHead;  

    m_pHead = p;  

}  

  

BOOL CSimpleList::Remove(void* p)  

{  

    if (p == NULL)  

    {  

        return FALSE;  

    }  

  

    BOOL bResult = FALSE;  

    if (p == m_pHead)  

    {  

        m_pHead = *GetNextPtr(m_pHead);  

        bResult = TRUE;  

    }  

    else  

    {  

        void* pTest = m_pHead;  

        while (pTest != NULL && *GetNextPtr(pTest) != p)  

        {  

            pTest = *GetNextPtr(pTest);  

        }  

        if (pTest != NULL)  

        {  

            *GetNextPtr(pTest) = *GetNextPtr(p);  

            bResult = TRUE;  

        }  

    }  

  

    return bResult;  

}  

  

void* CNoTrackObject::operator new(size_t nSize)  

{  

    void* p = ::GlobalAlloc(GPTR, nSize);  

    return  p;  

}  

  

void CNoTrackObject::operator delete(void* p)  

{  

    if (p!=NULL)  

    {  

        ::GlobalFree(p);  

    }  

}
 

afxatl.h文件:

#ifndef _AFXTLS_H_H  

#define _AFXTLS_H_H  

#include <Windows.h>  

  

class CSimpleList  

{  

public:  

    CSimpleList(int nNextOffset=0);  

    void Construct(int nNextOffset);  

    BOOL IsEmpty() const;  

    void AddHead(void* p);  

    void RemoveAll();  

    void* GetHead() const;  

    void* GetNext(void* p) const;  

    BOOL Remove(void* p);  

  

    //为实现接口所需要的成员  

    void* m_pHead;  

    int m_nNextOffset;  

    void** GetNextPtr(void* p) const;  

};  

  

//类的内联函数  

inline CSimpleList::CSimpleList(int nNextOffset)  

{m_pHead = NULL; m_nNextOffset = nNextOffset;}  

  

inline void CSimpleList::Construct(int nNextOffset)  

{m_nNextOffset = nNextOffset;}  

  

inline BOOL CSimpleList::IsEmpty() const      

{return m_pHead==NULL;}  

  

inline void CSimpleList::RemoveAll()  

{m_pHead=NULL;}  

  

inline void* CSimpleList::GetHead() const  

{return m_pHead;}  

  

inline void* CSimpleList::GetNext(void* preElement) const  

{  

    return *GetNextPtr(preElement);  

}  

  

inline void** CSimpleList::GetNextPtr(void* p) const  

{  

    return (void**)((BYTE*)p + m_nNextOffset);  

}  

  

class CNoTrackObject  

{  

public:  

    void* operator new(size_t nSize);  

    void operator delete(void*);  

    virtual ~CNoTrackObject(){};  

};  

  

template<class TYPE>  

  

class CTypedSimpleList:public CSimpleList  

{  

public:  

    CTypedSimpleList(int nNextOffset=0)  

        :CSimpleList(nNextOffset){}  

    void AddHead(TYPE p)  

    {  

        CSimpleList::AddHead((void*)p);  

    }  

  

    TYPE GetHead()  

    {  

        return (TYPE)CSimpleList::GetHead();  

    }  

  

    TYPE GetNext(TYPE p)  

    {  

        return (TYPE)CSimpleList::GetNext((void*)p);  

    }  

  

    BOOL Remove(TYPE p)  

    {  

        return CSimpleList::Remove(p);  

    }  

  

    operator TYPE()  

    {  

        return (TYPE)CSimpleList::GetHead();  

    }  

};  

#endif

希望本文所述对大家的C++程序设计有所帮助。