惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Hugging Face - Blog
Hugging Face - Blog
云风的 BLOG
云风的 BLOG
大猫的无限游戏
大猫的无限游戏
M
MIT News - Artificial intelligence
L
LangChain Blog
阮一峰的网络日志
阮一峰的网络日志
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Recent Announcements
Recent Announcements
IT之家
IT之家
Google DeepMind News
Google DeepMind News
罗磊的独立博客
爱范儿
爱范儿
Last Week in AI
Last Week in AI
人人都是产品经理
人人都是产品经理
U
Unit 42
MongoDB | Blog
MongoDB | Blog
S
SegmentFault 最新的问题
B
Blog
博客园 - 叶小钗
月光博客
月光博客
Stack Overflow Blog
Stack Overflow Blog
V
Visual Studio Blog
C
Check Point Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知

博客园 - 吴文力

VC 开机自动启动程序代码 Symbian中音频API的使用(摘录) symbian 游戏开发中一些技术细节(摘录) Symbian中声音处理 动态库的调用等技术 VC小技巧 15个问题 - 吴文力 - 博客园 VC 常见问题百问 VC/MFC Q&A 200409 DELL 电脑的区别 报表式CListCtrl的使用详解初稿 俄罗斯科学家语出惊人:怀孕前就能预设生男生女 PE文件格式详解 怎样在目录中寻找文件 WinNT & Win2K下实现进程的完全隐藏——宿主程序 木马病毒是如何利用文件关联和设置名感染的 104种清除木马完全攻略 Programming Applications for Microsoft Windows(四) Programming Applications for Microsoft Windows(三) Programming Applications for Microsoft Windows(二)
如何让程序自动管理线程
吴文力 · 2006-01-05 · via 博客园 - 吴文力

引言
多线程是一种很好的程序机制,使用线程可以充分的利用电脑资源,进行并行的业务处理。不过好的东西总有它的不足。线程是好,不过滥用,或管理不当就会造成线程混乱,内存漏洞,造成电脑速度变慢,反应迟钝。

想法
于是有人提出能不能让线程自己管理自己,把这复杂的工作交给电脑来处理。笔者经过多年的实践,终于用VC++实现了这一目的。
大家知道在VC++中我们可以用CreateThread创建一个线程,该函数返回这线程的Handle,以后我们就可以用这个Handle来管理这个线程的。于是我们可以做一个类名为ThreadManager,来管理这些Handle,并随时监控这些线程的状态。
总的思想就是这样,不过为了方便使用,我们最好把这个类封装成DLL的形式,这样以后我们在任何程序中都可以很方便的用该类来管理线程了(当然如果你有兴趣,也可以用COM模型来实现)。

实现
因为我们要把一切工作全交给ThreadManager,所以线程的创建,监控,删除都将在该类中实现,而我们仅要做的就是把线程函数名和线程参数传给ThreadManager类,于是我们定义该类构造函数为:

ThreadManager(ThreadPrc threadpro,LPVOID pParam);

该类还要能启动线程,于是我们又定义一个启动函数:

RunThread();

另外我们有时还要能获得线程的Handle,于是又定义一个函数:

HANDLE GetThreadHandle();

而该类唯一的成员参数就是Handle:

HANDLE m_Handle;

于是ThreadManager定义如下:

typedef DWORD (WINAPI *ThreadPro)(LPVOID);
class  CThreadManager : public CObject
{
	DECLARE_DYNAMIC( CThreadManager ) 
public:
	CThreadManager( ThreadPrc threadpro, LPVOID pParam);
	~CThreadManager();
	CBOOL RunThread();
	HANDLE GetThreadHandle() const { return( m_Handle ); };  
private:
	HANDLE m_Handle;
};

显然,我们仅有这一个类还不能完成我们所需的工作,我们还要一个负责具体监控的ThreadTask类,ThreadTask类中有一个监控线程ThreadTaskFunc( )负责监控并删除线程。该类定义如下:

class CThreadTask : public CObject
{
DECLARE_DYNAMIC( CThreadTask )
public:
	CThreadTask();  //构造函数
	~CThreadTask();
	CBOOL IsValid();  
	void AddHandle( CONST HANDLE cHandle );  //添加线程句柄到m_ObList中
	 
	void CloseThreadHandles();    //(关闭线程)
	static CThreadTask& GetCThreadTask();    //用于在Managerthread类中获得ThreadTask类的指针

	CObList	m_ObList;//线程句柄组
	HANDLE m_Handle;//线程句柄
	 
	BOOL m_bKeepGoing;//是否已运行
};

IMPLEMENT_DYNAMIC( CThreadCareTaker, CObject )

其中IsValid()是用于检验ThreadTaskFunc()是否已动行了,其它意思都很明显。

流程图
总的流程图如下:

具体实现
下面给出它的具体实现。

ThreadTask::ThreadTask()
{
  m_bKeepGoing = TRUE;
  //表示已运行
  DWORD nThreadId = 0;
  //创建管理线程
  m_Handle = (HANDLE)::CreateThread(NULL,0,ThreadTaskpro,0,0,&nThreadId );
}
void ThreadTask::AddHandle( CONST HANDLE cHandle )
{
	CHandle *pHandle = new CHandle;
	pHandle->m_ThreadHandle = cHandle;
	m_ObList.AddTail( pHandle );
	 
}
void ThreadTask::CloseThreadHandles()
{
	if ( m_ObList.GetCount() )
	{
		POSITION pos1, pos2;
		CHandle *pHandle = (CHandle *)NULL;  
		//(CHandle类相当简单,只有一个成员函数m_ThreadHandle)
		DWORD dwExitCode = 0L;
		for( pos1=m_ObList.GetHeadPosition(); (pos2=pos1)!=POSITION(NULL); )
		{
			//历遍所有已有的线程句柄
			pHandle = DYNAMIC_DOWNCAST( CHandle, m_ObList.GetNext( pos1 ) );
			//获得第pos1个handle
			VERIFY( ::GetExitCodeThread( pHandle->m_ThreadHandle, &dwExitCode ) );
			//获得线程pHandle的当前状态
			if ( dwExitCode != STILL_ACTIVE )
			//如果已完成
			{
				//释放当前句柄
				m_ObList.RemoveAt( pos2 );	 
		 
				VERIFY( ::CloseHandle( pHandle->m_ThreadHandle ) );
				delete pHandle;
				pHandle = (CHandle *)NULL;
			}
		}
	}
}

ThreadTask::~ThreadTask()
{

}

ThreadTask & ThreadTask::GetThreadTask()
{
	//返回静态ThreadTask对象,以便ThreadManager类调用
	static ThreadTask  Taker;
	return(Taker);
}

BOOL ThreadTask::IsValid()
{
	//是否已运行
	BOOL bValid_Status = FALSE;
	if ( (this != NULL) && AfxIsValidAddress( this, sizeof( ThreadTask ) ) )
		bValid_Status = TRUE;
	return( bValid_Status );
}

下面介绍线程ThreadTaskpro(); 该线程最主要的目的就是调用ThreadTask的CloseThreadHandles()函数,实现如下:

DWORD WINAPI ThreadTaskpro( LPVOID pParam  )
{
 
	HANDLE hCurrentThread = GetCurrentThread();
	//获得该线程句柄
	SetThreadPriority( hCurrentThread, THREAD_PRIORITY_LOWEST );
	//设为最低
	while ( ThreadTask::GetThreadTask().m_bKeepGoing )

	{
    Sleep(500);
	//休息500mms
 
		ThreadTask::GetThreadTask().CloseThreadHandles();
	}
 
	SetThreadPriority( hCurrentThread, THREAD_PRIORITY_NORMAL );
	return( 0 );
}

ThreadTask类到这就介绍完了,下面我们看看ThreadManager类的实现,其实它的工作已很小,就是启动要管理的线程(在构造函数中完成),并控制ThreadTask类。具体实现:

ThreadManager::ThreadManager(ThreadPro threadpro,  LPVOID pParam)
{

	DWORD nThreadId = 0;
	 _ASSERTE( ThreadTask::GetThreadTask().IsValid() );
	//运行ThreadTask类

	m_Handle = (HANDLE)::CreateThread(NULL,0,threadpro,(LPVOID)pParam,0,&nThreadId );
	//创建要管理的线程,并返回句柄
	if ( ThreadTask::GetThreadTask().m_bKeepGoing )
	{
		//如果ThreadTask运行了的话 
		ASSERT( m_Handle );
		ThreadTask::GetThreadTask().AddHandle( m_Handle );
		//把句柄加入ThreadTask类中,以便管理
	} 
}

ThreadManager::~ThreadManager()
{

}

BOOL  ThreadManager::RunThread()
{
	//运行线程
	return( ::ResumeThread( m_Handle ) != 0xFFFFFFFF );
}

整在机制就介绍完了。

使用方法

使用方法相当简单,比如说,我要运行进程MyThread1,并传入参数m_pro,只要用以下代码就可以了:

 ThreadManager ThreadManager( &MyThread1, (LPVOID)m_pro );
 	ThreadManager.RunThread();

就可以了,用这种方法创的线程,会自动由ThreadManager类管理,并在完成的工作时,自动释放线程资源。 我做了一个示例,大家可以试着运行一下。
http://www.vckbase.com/document/viewdoc/?id=454