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++程序设计有所帮助。