多线程扫描文件卡死,求解

MagicFuzzX 2012-07-09 01:36:25
核心代码如下:

#pragma once
#include <Windows.h>
#include <process.h>
#include <atlstr.h>
#include <vector>
#include <stack>
using namespace std;

#define MAXTHREADS 64

class CFileScan
{
public:
CFileScan(void);
~CFileScan(void);
ULONG GetFileCount(void);
BOOL BeginScan(LPCWSTR lpTargetDir,LPCWSTR lpExt,ULONG uThreadCounts);
private:
static UINT __stdcall ThreadFun(void* Param);
void SearchFile(void);
private:
stack<CString,vector<CString>> m_stkPath; //用于存储路径
LONG m_lResultCnt; //保存文件数
CString m_strExt; //保存拓展名字符串
HANDLE m_hDirEvent; //文件夹事件对象
HANDLE m_hExitEvent; //退出事件对象
ULONG m_uThread; //线程活动数量
CRITICAL_SECTION m_cs; //临界区对象,保持线程同步
};






#include "FileScan.h"
#include "DebugHelp.h"

CFileScan::CFileScan(void)
{
m_lResultCnt = 0;
m_uThread = 0;
InitializeCriticalSection(&m_cs);
m_hDirEvent = CreateEventW(NULL,FALSE,FALSE,NULL);
m_hExitEvent = CreateEventW(NULL,FALSE,FALSE,NULL);
}

CFileScan::~CFileScan(void)
{
CloseHandle(m_hDirEvent);
m_hDirEvent = INVALID_HANDLE_VALUE;
CloseHandle(m_hExitEvent);
m_hExitEvent = INVALID_HANDLE_VALUE;
DeleteCriticalSection(&m_cs);
}

BOOL CFileScan::BeginScan(LPCWSTR lpTargetDir,LPCWSTR lpExt,ULONG uThreadCounts)
{
if (!GOOD_HANDLE(m_hDirEvent))
{
DisplayInfoW(__FUNCTIONW__,L"DirEvent is invalid,return false");
return FALSE;
}
if (!GOOD_HANDLE(m_hExitEvent))
{
DisplayInfoW(__FUNCTIONW__,L"ExitEvent is invalid,return false");
return FALSE;
}
if (uThreadCounts > MAXTHREADS)
{
DisplayInfoExW(__FUNCTIONW__,L"ThreadCounts = %d is bigger than %d",uThreadCounts,MAXTHREADS);
return FALSE;
}
m_strExt = lpExt;

m_stkPath.push(lpTargetDir);
m_uThread = uThreadCounts;

HANDLE h[MAXTHREADS];
for(ULONG i = 0; i < m_uThread; i++)
{
h[i] = (HANDLE)_beginthreadex(NULL,0,&CFileScan::ThreadFun,static_cast<LPVOID>(this),0,NULL);
}
WaitForSingleObject(m_hExitEvent,INFINITE);
for(ULONG j = 0; j < m_uThread; j++)
{
CloseHandle(h[j]);
h[j] = INVALID_HANDLE_VALUE;
}
return TRUE;
}

ULONG CFileScan::GetFileCount(void)
{
return m_lResultCnt;
}

UINT __stdcall CFileScan::ThreadFun(void* Param)
{
static_cast<CFileScan*>(Param)->SearchFile();
return 0;
}

void CFileScan::SearchFile(void)
{
WIN32_FIND_DATA FindFileData;
HANDLE hListFile = INVALID_HANDLE_VALUE;
BOOL bActive = TRUE; //提示当前线程的状态
CString strFilePath;
CString strFullPath;
while(TRUE)
{
/*判断路径栈是否为空,为空设置线程状态,不为空则取得顶部路径*/
EnterCriticalSection(&m_cs);
if(m_stkPath.empty())
{
bActive = FALSE;
}
else
{
strFilePath = m_stkPath.top();
m_stkPath.pop();
}
LeaveCriticalSection(&m_cs);

/*判断线程应有状态,如果状态为假,进入等待*/
if(!bActive)
{
EnterCriticalSection(&m_cs);
m_uThread--;
if(m_uThread==0)
{
LeaveCriticalSection(&m_cs);
break;
}
LeaveCriticalSection(&m_cs);
ResetEvent(m_hDirEvent);
WaitForSingleObject(m_hDirEvent,INFINITE);
/*线程再次活动后,进入下一轮循环*/
EnterCriticalSection(&m_cs);
m_uThread++;
LeaveCriticalSection(&m_cs);
bActive = TRUE;
continue;
}

if (strFilePath.Right(1) != L"\\")
{
strFilePath += L"\\";
}
strFilePath += L"*.*";
hListFile = FindFirstFile(strFilePath,&FindFileData);
if (GOOD_HANDLE(hListFile))
{
do
{
strFullPath = strFilePath.TrimRight(L"*.*") + FindFileData.cFileName;
if(lstrcmp(FindFileData.cFileName,L".") == 0||lstrcmp(FindFileData.cFileName,L"..") == 0)
{
continue;
}

if(FindFileData.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY)
{
EnterCriticalSection(&m_cs);
m_stkPath.push(strFullPath);
LeaveCriticalSection(&m_cs);
SetEvent(m_hDirEvent);
}
else
{
EnterCriticalSection(&m_cs);
int curPos = 0;
CString strExt = strFullPath.Right(3);
while(TRUE)
{
CString resToken = m_strExt.Tokenize(L"|", curPos);
if(resToken.IsEmpty())
{
break;
}
if (0 == strExt.CompareNoCase(resToken))
{
InterlockedIncrement((LPLONG)&m_lResultCnt);
DisplayInfoW(__FUNCTIONW__,strFullPath.GetBuffer());
}
}
LeaveCriticalSection(&m_cs);
}
}
while(FindNextFile(hListFile, &FindFileData));
FindClose(hListFile);
hListFile = INVALID_HANDLE_VALUE;
}
else
{
//部分文件夹本来就无法打开,比如E:\System Volume Information\*.*
//此时如果输出错误的话,影响审美
//DWORD dwError = GetLastError();
//SetLastError(dwError);
//DisplayErrorW(__FUNCTIONW__,dwError,L"FindFirstFile");
}
}
SetEvent(m_hDirEvent);
if(WaitForSingleObject(m_hDirEvent,0) != WAIT_TIMEOUT)
{
SetEvent(m_hExitEvent);
}
}




CFileScan scan;
scan.BeginScan(L"E:",L"txt|doc",5);
ULONG uFileCount = scan.GetFileCount();
DisplayInfoExW(__FUNCTIONW__,L"file counts = %d",uFileCount);


有一定机率程序会失去反映,扫描不动了,也木有输出了,求各位大牛指点
...全文
261 6 打赏 收藏 转发到动态 举报
写回复
用AI写文章
6 条回复
切换为时间正序
请发表友善的回复…
发表回复
fronz 2012-07-09
  • 打赏
  • 举报
回复
卡死的原因需要调试来分析。关注
如果是多线程搜索一个目录有点没必要,可以让多线程搜索不同目录,程序的结构设计可能复杂些,遇空目录或遇到短目录就重新分配新任务
Yofoo 2012-07-09
  • 打赏
  • 举报
回复
卡死的时候调试, 暂停看callstack, 也可以看m_cs的值(调试信息)
hztj2005 2012-07-09
  • 打赏
  • 举报
回复
h[i] = (HANDLE)_beginthreadex(NULL,0,&CFileScan::ThreadFun,static_cast<LPVOID>(this),0,NULL);

这句中static_cast<LPVOID>(this)是传参数吧? 你这样传给子线程的参数不都是一样的吗?

比如说开始路径是c:\test,如果有4个子线程,那么每个子线程都从c:\test开始,自然会卡住。
oyljerry 2012-07-09
  • 打赏
  • 举报
回复
多增加一些Log等,来定位,估计什么地方死锁了。
还可以当程序没响应的时候生成dump,然后来分析
MagicFuzzX 2012-07-09
  • 打赏
  • 举报
回复


http://topic.csdn.net/u/20120708/21/982ffb20-7948-444d-8d05-3b51eff1f6d8.html

这里还有一个姊妹贴

16,471

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • Web++
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧