字符串处理算法(五)多线程实现代码行数统计。[风林火山]


实现如下:

//文件类型
enum E_FILETYPE 
{
	E_C,
	E_JAVA
};

//文件行数信息
struct T_CodeFileMsg
{
	int nTaskId;				//任务Id
	string FileName;			//文件名称
	E_FILETYPE eFiletype;		//文件类型
	int nTotalLine;				//总行数
	int nEmptyLine;				//空行数
	int nCodeLine;				//代码行数
	int nNoteLine;				//注释行数
	T_CodeFileMsg()
	{
		nTotalLine = 0;
		nEmptyLine = 0;
		nCodeLine = 0;
		nNoteLine = 0;
	}
};


#define	MAX_WORKTHREAD		5		//线程最大数
#define	MAX_LEN				1024	//路径最大长度
#define MAX_CHAR			1024	//一行最大字符数
//线程函数
DWORD WINAPI ReadFileThread(LPVOID lpParam);  
DWORD WINAPI WorkThread(LPVOID lpParam); 

//线程句柄
DWORD g_dwReadFileThreadID;  
DWORD g_dwTaskThread;
DWORD g_dwWorkThread[MAX_WORKTHREAD];

//事件句柄
HANDLE g_EventReadFileHandle;
HANDLE g_EventReadFinishHandle;

//临界区
CRITICAL_SECTION g_cs;
CRITICAL_SECTION g_MsgQueue;
CRITICAL_SECTION g_task;
CRITICAL_SECTION g_MsgMap;


//数据
map<int, int>m_task;
std::deque<int> m_MsgQueue;
std::deque<int> m_FileQueue;//任务队列
std::map<int, T_CodeFileMsg*> m_FileMsgMap;//处理文件与文件行数信息

int WorkThreadCout = 0;
int nTotalTaskCount =0;
int nWorkTaslCount=0;
int nTaskBeginTime;
int nReadFileFinish=0;
int nInitCount= 0;
int nWorkFlag = 0;
bool bRunFlag = TRUE;
char g_workPath[MAX_LEN];

bool bReadFileFlag=TRUE;

int g_nTaskId=0;


int main()
{ 
	int i;
	cout << "#####代码行数统计测试开始#####" <<endl;

	cout << "Main thread is running." << endl;  
	
	//初始化临界区
	InitializeCriticalSection(&g_cs);
	InitializeCriticalSection(&g_MsgQueue);
	InitializeCriticalSection(&g_MsgMap);
	
	g_EventReadFileHandle = ::CreateEvent(NULL,TRUE,TRUE,NULL);
	g_EventReadFinishHandle = ::CreateEvent(NULL,TRUE,TRUE,NULL);
	
	//创建线程
	HANDLE hRFTHandle = CreateThread(NULL, 0, ReadFileThread, NULL, 0, &g_dwReadFileThreadID);  
	
	HANDLE hWTHandle[MAX_WORKTHREAD];
	
	for (i=0; i<MAX_WORKTHREAD; i++)
	{
		int* nTemp = new int;//如果不new,最后打印出来的WorkThread(LPVOID lpParam)的都是10
								//nTemp = &i;和*nTemp = i;区别。
		*nTemp = i;
		hWTHandle[i] = CreateThread(NULL, 0, WorkThread, nTemp, 0, &g_dwWorkThread[i]); 
		WorkThreadCout ++;
		m_task[i] = 0;
		Sleep(100);
	}
	
	while (TRUE)
	{
		
		if (nWorkFlag == 0)
		{
			printf("输入要统计文件的路径或end退出
");
			scanf("%s", g_workPath);


			DeleteMap();
			g_nTaskId = 0;
			nWorkTaslCount = 0;
			
			if (strcmp(g_workPath, "end") == 0)
			{
				bReadFileFlag = FALSE;//读文件线程标志
				SetEvent(g_EventReadFileHandle);//读事件
				bRunFlag = FALSE;//让线程退出
				break;
			}
			
			SetEvent(g_EventReadFileHandle);//读事件
			
			nWorkFlag = 1;
		}

		ResetEvent(g_EventReadFinishHandle);
		WaitForSingleObject(g_EventReadFinishHandle, INFINITE);

		if (nReadFileFinish == 1)
		{
			PrintMsg();
		}
	}
	
	Sleep(3000);

	DeleteMap();
	
	CloseHandle(hRFTHandle);
	for (i=0; i<MAX_WORKTHREAD; i++)
	{
		CloseHandle(hWTHandle[i]);
	}
	
	CloseHandle(g_EventReadFileHandle);   
	CloseHandle(g_EventReadFinishHandle);  
	
	DeleteCriticalSection(&g_cs);
	DeleteCriticalSection(&g_MsgQueue);
	DeleteCriticalSection(&g_MsgMap);
	
	
	cout << "Main thread is end." << endl;
	
	cout << "#####代码行数统计测试结束#####" <<endl;
	//system("pause");  
	return 0;  
}

int InitData()
{
	return 0;
}

int DeleteMap()
{
	std::map<int, T_CodeFileMsg*>::iterator IterFile;
	for(IterFile=m_FileMsgMap.begin(); IterFile!=m_FileMsgMap.end(); IterFile++)
	{
		T_CodeFileMsg* file = (*IterFile).second;

		delete file;
		file = NULL;
	}

	m_FileMsgMap.clear();

	return 0;
}

DWORD WINAPI ReadFileThread(LPVOID lpParam)  
{   
	// cout << "No." << g_dwThreadID << " thread is running." << endl;  
	while (bRunFlag)  
	{  
		EnterCriticalSection(&g_cs);
		cout << "ReadFileThread " << g_dwReadFileThreadID << " thread is running." << endl;
		LeaveCriticalSection(&g_cs);
		
		ResetEvent(g_EventReadFileHandle);
		WaitForSingleObject(g_EventReadFileHandle, INFINITE);
		if (bReadFileFlag)
		{
			int nTemp = DirectoryList(g_workPath);//nReadFileFinish
			nReadFileFinish = nTemp;
			if (nTemp == 1)
			{
				PrintFile();
				nWorkFlag = 0;
				nTotalTaskCount = g_nTaskId;
			}
			else
			{
				nWorkFlag = 0;
			}

			SetEvent(g_EventReadFinishHandle);
		}
		
		Sleep(1000);
	}  
	
	cout << "ReadFileThread " << g_dwReadFileThreadID << " end" << endl;
	
	return 0;  
} 

DWORD WINAPI WorkThread(LPVOID lpParam)  
{   
	// cout << "No." << g_dwThreadID << " thread is running." << endl;  

	int* nRemp = (int*)lpParam;
	while (bRunFlag)  
	{  
		int n = -1;
		T_CodeFileMsg* pCFMsg=NULL;
		
		EnterCriticalSection(&g_cs);
		//cout << "No " << *nRemp << ", " << g_dwWorkThread[*nRemp] << " thread is running." << endl;
		LeaveCriticalSection(&g_cs);
		
		EnterCriticalSection(&g_MsgQueue);
		if (!m_FileQueue.empty())
		{
			n = m_FileQueue.front();
			m_FileQueue.pop_front();
			if (nWorkTaslCount == 0)
			{
				nTaskBeginTime = GetTickCount();
			}
			nWorkTaslCount++;
			
			m_task[*nRemp]++;
		}

		LeaveCriticalSection(&g_MsgQueue);
		
		EnterCriticalSection(&g_MsgMap);
		if ( n>= 0)//没有这个,在开始的时候n=-1会造成溢出。
			pCFMsg = m_FileMsgMap[n];
		LeaveCriticalSection(&g_MsgMap);

		EnterCriticalSection(&g_cs);
		//cout << "No:" << *nRemp << ", " << n << endl;
		if (pCFMsg!=NULL)
		{
			cout << pCFMsg->FileName.c_str() << endl;
		}
		LeaveCriticalSection(&g_cs);

		if (pCFMsg!=NULL && n>=0)
		{
			ProcessFile(pCFMsg, n);
			Sleep(20);
		}
		else
			Sleep(2000);	
	} 
	
	delete nRemp;
	nRemp = NULL;
	
	cout << "No " << lpParam << " end" << endl;
	
	return 0;  
}

//根据文件类型处理
int ProcessFile(T_CodeFileMsg* pTCFMsg, int n)
{
	EnterCriticalSection(&g_MsgMap);
	string tempFile = pTCFMsg->FileName;
	E_FILETYPE c_type = pTCFMsg->eFiletype;
	LeaveCriticalSection(&g_MsgMap);

	switch(c_type)
	{
	case E_C:
		ProcessCFile(pTCFMsg, tempFile.c_str(), n);
		break;
	case E_JAVA:
		ProcessJavaFile(pTCFMsg, tempFile.c_str(), n);
		break;
	default:
		break;
	}

	return 0;
}

int ProcessCFile(T_CodeFileMsg* pTCFMsg, char* strFile, int n)
{
	ifstream in;
	char buf[MAX_CHAR] = {0};
	bool bNoteFlag = FALSE;
	int nNoteLine = 0;
	int nEmptyLine = 0;
	int nCodeLine = 0;
	int nTotalLine = 0;

	in.open(strFile);
	while(in.getline(buf, sizeof(buf))) 
	{
		nTotalLine++;
		char* p = buf; 
		while((*p ==' ' || *p=='	')) p++;

		if (!bNoteFlag)
		{
			if (*p == 0)
			{
				nEmptyLine++;
				cout << nTotalLine <<endl;

			}
			else if (strncmp(p, "/*", 2)==0) 
			{
				char* q = buf+strlen(buf)-1;
				while((*q ==' ' || *q=='	')) q--;
				
				q--;

				//判断是不是/*AAA*/
				if (strncmp(q, "*/", 2)==0)
				{
				}
				else
					bNoteFlag = TRUE;

				nNoteLine++;
				cout << nTotalLine <<endl;
			}
			else if (strncmp(p, "//", 2)==0) 
			{
				nNoteLine++;
				cout << nTotalLine <<endl;
			}
			else
			{
				nCodeLine++;
			}
		}
		else
		{
			if (*p == 0)
			{
				nNoteLine++;
				cout << nTotalLine <<endl;
			}
			else if (strncmp(p, "*/", 2)==0) 
			{
				bNoteFlag = FALSE;
				nNoteLine++;
				cout << nTotalLine <<endl;
			}
			else 
			{
				nNoteLine++;
				cout << nTotalLine <<endl;

				char* q = buf+strlen(buf)-1;
				while((*q ==' ' || *q=='	')) q--;
				
				q--;
				
				if (strncmp(q, "*/", 2)==0)
				{
					bNoteFlag = FALSE;
				}
			}
		}

		memset(buf, 0, MAX_CHAR);
	}

	EnterCriticalSection(&g_MsgMap);
	pTCFMsg->nCodeLine = nCodeLine;
	pTCFMsg->nEmptyLine = nEmptyLine;
	pTCFMsg->nNoteLine = nNoteLine;
	pTCFMsg->nTotalLine = nTotalLine;
	m_FileMsgMap[n] = pTCFMsg;
	LeaveCriticalSection(&g_MsgMap);

	return 0;
}

int ProcessJavaFile(T_CodeFileMsg* pTCFMsg, char* strFile, int n)
{
	return 0;
}

int AddFile2Map(char* pFile)
{
	string strFile = strlwr(pFile);
	
	int nRet = strFile.find(".", 0);
	
	if (nRet>0)
	{
		string Temp;
		int nLen = strFile.size();
		Temp = strFile.substr(nRet, strFile.size()-nRet);
		
		if (strcmp(Temp.c_str(),".c")==0 || strcmp(Temp.c_str(),".cpp")==0 || strcmp(Temp.c_str(),".h")==0)
		{		
			T_CodeFileMsg* pTemp = new T_CodeFileMsg;
			m_FileMsgMap[g_nTaskId] = pTemp;

			//m_FileMsgMap[g_nTaskId] = new T_CodeFileMsg;
			//T_CodeFileMsg* pTemp = m_FileMsgMap[g_nTaskId];
			pTemp->eFiletype = E_C;
			pTemp->nTaskId = g_nTaskId;
			pTemp->FileName = pFile;
			//pTemp->FileName = new char[nLen+1];
			//memcpy(pTemp->FileName, strFile.c_str(), nLen);

			

			//m_FileMsgMap[g_nTaskId] = pTemp;
			//m_FileMsgMap.insert(pair <int, T_CodeFileMsg* >(g_nTaskId, pTemp));
			m_FileQueue.push_back(g_nTaskId);
			g_nTaskId++;
		}

	}
	return 0;
}

int DirectoryList(LPCSTR Path)
{
	WIN32_FIND_DATA FindData;
	HANDLE hError;
	int FileCount = 0;
	char FilePathName[MAX_LEN];
	// 构造路径
	char FullPathName[MAX_LEN];
	strcpy(FilePathName, Path);
	strcat(FilePathName, "\*.*");
	hError = FindFirstFile(FilePathName, &FindData);
	if (hError == INVALID_HANDLE_VALUE)
	{
		printf("搜索失败!
");
		return 0;
	}
	
	while(::FindNextFile(hError, &FindData))
	{
		// 过虑.和..
		if (strcmp(FindData.cFileName, ".") == 0
			|| strcmp(FindData.cFileName, "..") == 0 )
		{
			continue;
		}
		
		// 构造完整路径
		wsprintf(FullPathName, "%s\%s", Path,FindData.cFileName);
		FileCount++;
		
		AddFile2Map(FullPathName);
		
		// 输出本级的文件
		//printf("
%d  %s  ", FileCount, FullPathName);
		
		if (FindData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
		{
			//printf("<Dir>");
			DirectoryList(FullPathName);
		}			
	}
	
	return 1;
	
}

int PrintFile()
{
	EnterCriticalSection(&g_MsgMap);	
	std::map<int, T_CodeFileMsg*>::iterator IterFile;
	for(IterFile=m_FileMsgMap.begin(); IterFile!=m_FileMsgMap.end(); IterFile++)
	{
		T_CodeFileMsg* file = (*IterFile).second;
		
		//EnterCriticalSection(&g_cs);
		cout << endl;
		cout << file->FileName.c_str();
		cout << ", id:" << file->nTaskId;
		cout << ", nCodeLine:"<< file->nCodeLine;
		cout << ", nEmptyLine:"<< file->nEmptyLine;
		cout << ", nNoteLine:"<< file->nNoteLine;
		cout << ", nTotalLine:"<< file->nTotalLine;
		//LeaveCriticalSection(&g_cs);
		
	}
	LeaveCriticalSection(&g_MsgMap);

	return 0;
}

int PrintMsg()
{
	while (TRUE)
	{
		if (nWorkTaslCount == nTotalTaskCount)
		{
			std::map<int, int>::iterator IterCount;
			for(IterCount=m_task.begin(); IterCount!=m_task.end();IterCount++)
			{
				int nThreadId= (*IterCount).first;
				int nCount = (*IterCount).second;
				
				EnterCriticalSection(&g_cs);
				cout << "nThreadId:" << nThreadId << ", nCount:" << nCount<<endl;
				LeaveCriticalSection(&g_cs);
				
				(*IterCount).second = 0;
			}
			
			nWorkFlag = 0;
			
			PrintFile();

			break;
		}

		cout << "nWorkTaslCount:" << nWorkTaslCount << ", nTotalTaskCount:" << nTotalTaskCount <<endl;
		
		Sleep(1000);
	}
	
	return 0;
}


有兴趣的朋友可以自己试试,仅供参考。


转载请注明原创链接:http://blog.csdn.net/wujunokay/article/details/12586589






原文地址:https://www.cnblogs.com/fuhaots2009/p/3363646.html