C++实现多线程查找文件实例
主要是多线程的互斥文件的查找
多线程互斥的框架
//线程函数 UINTFinderEntry(LPVOIDlpParam) { //CRapidFinder通过参数传递进来 CRapidFinder*pFinder=(CRapidFinder*)lpParam; CDirectoryNode*pNode=NULL; BOOLbActive=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, } //从目录列表中成功取得了目录 <spanstyle="white-space:pre"> </span>...................... //if(pNode) //{ // deletepNode; // pNode=NULL; //} }//endwhile //促使一个搜索线程从WaitForSingleObject返回,并退出循环 ::SetEvent(pFinder->m_hDirEvent); //判断此线程是否是最后一个结束循环的线程,如果是就通知主线程 if(::WaitForSingleObject(pFinder->m_hDirEvent,0)!=WAIT_TIMEOUT) { ::SetEvent(pFinder->m_hExitEvent); } return1; }
查找文件的框架:
//从目录列表中成功取得了目录 WIN32_FIND_DATAfileData; HANDLEhFindFile; //生成正确的查找字符串 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是constint类型,只能通过这种方式初始化 CRapidFinder::CRapidFinder(intnMaxThread):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(LPCTSTRlpszFileName) { //定义两个字符串 charstring[MAX_PATH]; charstrSearch[MAX_PATH]; strcpy(string,lpszFileName); strcpy(strSearch,m_szMatchName); //将字符串大写 _strupr(string); _strupr(strSearch); //比较string中是否含有strSearch if(strstr(string,strSearch)!=NULL) { returnTRUE; } returnFALSE; } //线程函数 UINTFinderEntry(LPVOIDlpParam) { //CRapidFinder通过参数传递进来 CRapidFinder*pFinder=(CRapidFinder*)lpParam; CDirectoryNode*pNode=NULL; BOOLbActive=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_DATAfileData; HANDLEhFindFile; //生成正确的查找字符串 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=newCDirectoryNode; 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,肯定会出错 //deletep; //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) //{ // deletepNode; // pNode=NULL; //} }//endwhile //促使一个搜索线程从WaitForSingleObject返回,并退出循环 ::SetEvent(pFinder->m_hDirEvent); //判断此线程是否是最后一个结束循环的线程,如果是就通知主线程 if(::WaitForSingleObject(pFinder->m_hDirEvent,0)!=WAIT_TIMEOUT) { ::SetEvent(pFinder->m_hExitEvent); } return1; } void main() { printf("start:\n"); CRapidFinder*pFinder=newCRapidFinder(64); CDirectoryNode*pNode=newCDirectoryNode; charszPath[]="c:\\"; charszFile[]="config"; strcpy(pNode->szDir,szPath); pFinder->m_listDir.AddHead(pNode); strcpy(pFinder->m_szMatchName,szFile); pFinder->m_nThreadCount=pFinder->m_nMaxThread; //开始开启多线程 for(inti=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)deletepNode; if(pFinder!=NULL)deletepFinder; getchar(); return; }
rapidfinder.h文件如下:
#include"_AFXTLS_.H" structCDirectoryNode:publicCNoTrackObject { CDirectoryNode*pNext; charszDir[MAX_PATH]; }; classCRapidFinder { public: CRapidFinder(intnMaxThread);//构造函数 virtual~CRapidFinder(); //析构函数 BOOL CheckFile(LPCTSTRlpszFileName);//检查lpszFileName是否符合查找条件 int m_nResultCount;//找到的结果数量 int m_nThreadCount;//当前的线程数量 CTypedSimpleList<CDirectoryNode*>m_listDir;//查找目录 CRITICAL_SECTION m_cs; //共享 constint m_nMaxThread; //最大线程数量 char m_szMatchName[MAX_PATH];//要查找的名称 HANDLE m_hDirEvent; //添加新目录后置位 HANDLE m_hExitEvent; //所有线程退出时置位 };
下面这两个类就是实现了simplelist类和模板
_afxatl.cpp文件:
#include"_AFXTLS_.H" voidCSimpleList::AddHead(void*p) { *GetNextPtr(p)=m_pHead; m_pHead=p; } BOOLCSimpleList::Remove(void*p) { if(p==NULL) { returnFALSE; } BOOLbResult=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; } } returnbResult; } void*CNoTrackObject::operatornew(size_tnSize) { void*p=::GlobalAlloc(GPTR,nSize); return p; } voidCNoTrackObject::operatordelete(void*p) { if(p!=NULL) { ::GlobalFree(p); } }
afxatl.h文件:
#ifndef_AFXTLS_H_H #define_AFXTLS_H_H #include<Windows.h> classCSimpleList { public: CSimpleList(intnNextOffset=0); voidConstruct(intnNextOffset); BOOLIsEmpty()const; voidAddHead(void*p); voidRemoveAll(); void*GetHead()const; void*GetNext(void*p)const; BOOLRemove(void*p); //为实现接口所需要的成员 void*m_pHead; intm_nNextOffset; void**GetNextPtr(void*p)const; }; //类的内联函数 inlineCSimpleList::CSimpleList(intnNextOffset) {m_pHead=NULL;m_nNextOffset=nNextOffset;} inlinevoidCSimpleList::Construct(intnNextOffset) {m_nNextOffset=nNextOffset;} inlineBOOLCSimpleList::IsEmpty()const {returnm_pHead==NULL;} inlinevoidCSimpleList::RemoveAll() {m_pHead=NULL;} inlinevoid*CSimpleList::GetHead()const {returnm_pHead;} inlinevoid*CSimpleList::GetNext(void*preElement)const { return*GetNextPtr(preElement); } inlinevoid**CSimpleList::GetNextPtr(void*p)const { return(void**)((BYTE*)p+m_nNextOffset); } classCNoTrackObject { public: void*operatornew(size_tnSize); voidoperatordelete(void*); virtual~CNoTrackObject(){}; }; template<classTYPE> classCTypedSimpleList:publicCSimpleList { public: CTypedSimpleList(intnNextOffset=0) :CSimpleList(nNextOffset){} voidAddHead(TYPEp) { CSimpleList::AddHead((void*)p); } TYPEGetHead() { return(TYPE)CSimpleList::GetHead(); } TYPEGetNext(TYPEp) { return(TYPE)CSimpleList::GetNext((void*)p); } BOOLRemove(TYPEp) { returnCSimpleList::Remove(p); } operatorTYPE() { return(TYPE)CSimpleList::GetHead(); } }; #endif
希望本文所述对大家的C++程序设计有所帮助。