Monday, December 13, 2004

 

File find with source code

1. 运用多线程技术实现文件的快速搜索
作者:姜勇道
出处:http://www.vckbase.com/document/viewdoc.asp?id=445

其基本思想其实很简单,就是找到一个目录就开辟一个线程,文件的话当然在线程内就处理了。

基本数据结构如下:

首先要定义线程的参数结构用于文件信息的传递:
typedef struct tagTHREADPARAM {
CString strPath;
CString strFileName;
}THREADPARAM m_param;

因为线程要操纵全局变量,所以定义互斥体:CMutex m_mutexThreadCount,m_mutexThreadParam,m_mutexPath;

如果搜索完毕或搜索终止,要有事件通知,于是创建一个事件: CEvent m_event(FALSE,FALSE,NULL,NULL);

用CStringArray m_strPathArray存放结果

核心代码:

[code]
......
m_mutexThreadCount.Lock();
uThreadCount++;
m_mutexThreadCount.Unlock();
......

m_mutexThreadCount.Lock();
uThreadCount--;
//所有的线程完成,则激活事件,通知应用程序完成搜索(下同)
if(uThreadCount==0)
m_event.SetEvent();
m_mutexThreadCount.Unlock();
......
AfxBeginThread(GetFilePathThreadProc, &m_param, THREAD_PRIORITY_NORMAL);
::WaitForSingleObject(m_event.m_hObject,INFINITE);
......
[/code]

(按:操作系统的搜索功能是单线程的,但这样已经会使磁盘或CPU处于忙负荷,用多线程只会增加CPU的负荷,也不能减轻磁盘的负荷。不过,到是可以看看怎么玩CEvent)

2. 一个用多线程实现文件查找的例子
作者:Kelvin U.V
出处:http://www.vckbase.com/document/viewdoc.asp?id=449

这个更加复杂一些,增加了如下操作

//设置线程数及优先级
void ThreadSet(LONG MaxThreadCount=5,int priority=0);

//搜索选项
void FinderOption(FINDEROPTION FinderOption);

//查找操作
BOOL StartFinder(); //开始查找
void PauseFinder(); //暂停查找
void ResumeFinder(); //继续查找
void StopFinder(); //停止查找
void FinderReset(); //查找重置

每个线程通过自定义的消息与UI线程通信,反映当前的查找进度与查找结果。 //自定义通知消息=========================================================
//WM_THREADEXIT 主线程结束 WPARAM: 结束码
//WM_THREADCOUNT 活动线程数目 WPARAM: 线程数
//WM_FINDERITEM 查找结果 WPARAM: 结果字符串地址 LPARAM:文件属性
//WM_THREADPAUSE 程序暂停
//WM_FINDERFOLDER当前查找目录 WPARAM: 目录字符串地址
//========================================================

编程思路:

定义一个临时目录列表CStringList m_DirList; 线程每找到一个目录就将它放在m_DirList尾,若找到的是文件,就用MatchProc()进行比较,判断是否符合查找条件。若符合就向UI线程发送消息WM_FINDERITEM,以进行界面显示。然后,线程继续在当前目录中查找直到当前目录全部查找完毕。再从m_DirList队头取一个新的目录进行查找。

这里有一个要注意的地方就是m_DirList为每个线程所共有的资源,所以在访问m_DirList时要注意一下线程间的互斥,这可以用临界区操作来保证。

那么,如何来判断文件查找应该结束了呢?仅判断m_DirList为空是不够的,因为当m_DirList为空时,有可能还有活动的线程,这些活动的线程可能还会产生新的未查找的目录,故只有在m_DirList为空且当前的活动线程数为0时才可以断定查找结束。(这里的"活动线程"指正在进行查找操作的线程,"非活动线程"指处于等待新的待查目录状态的线程)

测试结果:

“程序编译运行后,仅进行文件名查找时经测试速度比Windows自带的查找程序稍快(Win9x的查找程序是独立的,而Win2000下是集成在Explorer中的),当线程数在5-10之间时速度最快,而超过50时速度反而变慢,这就说明了并不是线程越多越好。线程数过多,CPU的大部分开销花在线程间切换上,而且由于没有足够的待查目录,大多数的线程处在等待状态,占用了大量的系统资源,从而使速度变慢。当进行包含文字的查找时,我用的是KMP匹配算法,但是速度还是比Windows自带查找程序慢。”

(按:这篇文章明显认识到了线程不能太多。一般来说,Window现在倾向于开5-7个线程,比如Explorer,Internet Enplorer就开这么多。不过作者还不能很好的调配进程,"使用Sleep起一个延时作用,它把控制权先交到其他线程,当各线程运行检测到Event已经改变就执行相应操作
PumpMessage()",仍然未得线程池的精髓。另外,如果用户不坚持需要广度优先搜索的话,多线程实在没有太大必要。)

3. FindFile class for Windows projects
http://www.codeproject.com/file/win32findfile.asp
不便于移植,不过filter还行。

4. CFileFinder - Extend the functionality of CFileFind MFC class
By Samuel Gonzalo
http://www.codeproject.com/file/cfilefinderex.asp

(按:我很喜欢该作者的另外一个作品
CPath 1.2 - To work with path strings easily
http://www.codeproject.com/file/cpath.asp
作者在这里将两者结合得很好,我自己的搜索文件就是在这一基础上开发的。原文让我最不满意的两个地方实不能resume查询,GUI选项做的不够,不能直接Copy之。^_^)

(按:另外,看起来大家还都是喜欢CStringArray,没别的,就算MFC的STL封装不够快,可用起来舒服,又不容易错,谁不喜欢呢?
还有,说到GetLength64错误,这里可以参见
Bug in MFC's CFileFind::GetLength64()
http://www.codeproject.com/buglist/getlength64bug.asp.asp
what a ugly bug!



<< Home

This page is powered by Blogger. Isn't yours?