热门标签 | HotTags
当前位置:  开发笔记 > 开发工具 > 正文

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

这篇文章主要介绍了C++实现多线程查找文件实例,对于深入学习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, 
        } 
        //从目录列表中成功取得了目录 
      ...................... 
         
        //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  
#include  
#include  
 
//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;im_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 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  
 
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 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++程序设计有所帮助。


推荐阅读
  • 基于layUI的图片上传前预览功能的2种实现方式
    本文介绍了基于layUI的图片上传前预览功能的两种实现方式:一种是使用blob+FileReader,另一种是使用layUI自带的参数。通过选择文件后点击文件名,在页面中间弹窗内预览图片。其中,layUI自带的参数实现了图片预览功能。该功能依赖于layUI的上传模块,并使用了blob和FileReader来读取本地文件并获取图像的base64编码。点击文件名时会执行See()函数。摘要长度为169字。 ... [详细]
  • 搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的详细步骤
    本文详细介绍了搭建Windows Server 2012 R2 IIS8.5+PHP(FastCGI)+MySQL环境的步骤,包括环境说明、相关软件下载的地址以及所需的插件下载地址。 ... [详细]
  • 本文讨论了Alink回归预测的不完善问题,指出目前主要针对Python做案例,对其他语言支持不足。同时介绍了pom.xml文件的基本结构和使用方法,以及Maven的相关知识。最后,对Alink回归预测的未来发展提出了期待。 ... [详细]
  • 本文介绍了C#中生成随机数的三种方法,并分析了其中存在的问题。首先介绍了使用Random类生成随机数的默认方法,但在高并发情况下可能会出现重复的情况。接着通过循环生成了一系列随机数,进一步突显了这个问题。文章指出,随机数生成在任何编程语言中都是必备的功能,但Random类生成的随机数并不可靠。最后,提出了需要寻找其他可靠的随机数生成方法的建议。 ... [详细]
  • 本文介绍了在Hibernate配置lazy=false时无法加载数据的问题,通过采用OpenSessionInView模式和修改数据库服务器版本解决了该问题。详细描述了问题的出现和解决过程,包括运行环境和数据库的配置信息。 ... [详细]
  • Win10下游戏不能全屏的解决方法及兼容游戏列表
    本文介绍了Win10下游戏不能全屏的解决方法,包括修改注册表默认值和查看兼容游戏列表。同时提供了部分已经支持Win10的热门游戏列表,帮助玩家解决游戏不能全屏的问题。 ... [详细]
  • 如何在联想win10专业版中修改账户名称
    本文介绍了在联想win10专业版中修改账户名称的方法,包括在计算机管理中找到要修改的账户,通过重命名来修改登录名和属性来修改显示名称。同时指出了windows10家庭版无法使用此方法的限制。 ... [详细]
  • 本文讨论了如何优化解决hdu 1003 java题目的动态规划方法,通过分析加法规则和最大和的性质,提出了一种优化的思路。具体方法是,当从1加到n为负时,即sum(1,n)sum(n,s),可以继续加法计算。同时,还考虑了两种特殊情况:都是负数的情况和有0的情况。最后,通过使用Scanner类来获取输入数据。 ... [详细]
  • Windows下配置PHP5.6的方法及注意事项
    本文介绍了在Windows系统下配置PHP5.6的步骤及注意事项,包括下载PHP5.6、解压并配置IIS、添加模块映射、测试等。同时提供了一些常见问题的解决方法,如下载缺失的msvcr110.dll文件等。通过本文的指导,读者可以轻松地在Windows系统下配置PHP5.6,并解决一些常见的配置问题。 ... [详细]
  • 电脑公司win7剪切板位置及使用方法
    本文介绍了电脑公司win7剪切板的位置和使用方法。剪切板一般位于c:\windows\system32目录,程序名为clipbrd.exe。通过在搜索栏中输入cmd打开命令提示符窗口,并输入clip /?即可调用剪贴板查看器。赶紧来试试看吧!更多精彩文章请关注本站。 ... [详细]
  • Metasploit攻击渗透实践
    本文介绍了Metasploit攻击渗透实践的内容和要求,包括主动攻击、针对浏览器和客户端的攻击,以及成功应用辅助模块的实践过程。其中涉及使用Hydra在不知道密码的情况下攻击metsploit2靶机获取密码,以及攻击浏览器中的tomcat服务的具体步骤。同时还讲解了爆破密码的方法和设置攻击目标主机的相关参数。 ... [详细]
  • 本文介绍了C#中数据集DataSet对象的使用及相关方法详解,包括DataSet对象的概述、与数据关系对象的互联、Rows集合和Columns集合的组成,以及DataSet对象常用的方法之一——Merge方法的使用。通过本文的阅读,读者可以了解到DataSet对象在C#中的重要性和使用方法。 ... [详细]
  • 本文介绍了OC学习笔记中的@property和@synthesize,包括属性的定义和合成的使用方法。通过示例代码详细讲解了@property和@synthesize的作用和用法。 ... [详细]
  • Mac OS 升级到11.2.2 Eclipse打不开了,报错Failed to create the Java Virtual Machine
    本文介绍了在Mac OS升级到11.2.2版本后,使用Eclipse打开时出现报错Failed to create the Java Virtual Machine的问题,并提供了解决方法。 ... [详细]
  • win10系统搭建Java开发环境的操作方法
    本文介绍了win10系统搭建Java开发环境的详细操作方法,包括下载Windows10系统和Java SE,安装Java开发环境,设置变量等步骤。操作简单,只需按照指导进行即可。 ... [详细]
author-avatar
张哥他爹
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有