简介
虽然ATL和WTL提供了一个Win32处理可以参照的各种对象的最有用的包装类,线程仍然必须创建和控制使用的API函数和处理直接。诚然,这是不是一个很难的事情,但一个干净的面向对象的设计往往可以帮助避免在多线程应用程序中的错误。
类的集合,我会到目前经常被证明是非常有用的我。它包含了处理线程,以及包装,帮助落实工作人员和GUI线程的基类。线程句柄的包装类
没有太多说这些类。在通常由WTL的风格,CThreadT是围绕一个线程处理的包装模板类,它提供了大多数Win32 API函数,作为方法的线程句柄。
更方便的是,一个通常使用的模板实例CThread和CThreadHandle:CThread将关闭线程句柄,当它被破坏,而CThreadHandle不会,。创建一个线程
实现为静态方法CThreadT,创建线程:创建,这是一个包装周围_beginthreadex(或的CreateThread,如果最小的CRT使用"选项"设置)/ / ... ...。CThread线程= CThread:((LPTHREAD_START_ROUTINE)
60; MyThreadProc,pParam);/ / ...CThread和CThreadHandle其他方法CThreadT(句柄= NULL,DWORD = 0)环绕一个CThread实例给定的线程句柄和线程ID。还有一个拷贝构造函数,这将在给定的句柄调用DuplicateHandle。线程句柄和ID可以检索GetHandle()的getId()。方法打开,GetPriority,SetPriority,GetExitCode,GetThreadTimes,IsIOPending,恢复,暂停,终止和退出都是围绕各自的API函数,它们的名字大多是"线程"这个词的净包装。该方法加入执行WaitForSingleObject的线程句柄。GUI线程
GUI线程是从普通工人中,他们有一个消息队列的线程不同。这意味着,我们可以将邮件投递到一个GUI线程使用PostThreadMessage。
模板类CGuiThreadT,和它的实例CGuiThread,并CGuiThreadHandle,就像CThreadT类,为此额外的方法PostThreadMessage。
造成一个GUI线程退出,通常是一个WM_QUIT消息发布到自己的队列。这是通过调用PostQuitMessage方法。但是,这种方法不换行的同名的API,因为后者职位WM_QUIT调用线程,这并不总是相同。线程执行类
作为ATL和WTL往往区分一个对象和它的执行情况(比较CWindow的和CWindowImpl的)的句柄,我选择了我的线程类的设计(虽然两种情况都是不完全可比)。 CThreadImpl类提供了一个线程"实施"类的骨架。
来自CThreadImpllt线程类; TGT;和执行Run方法:类CWorkerThread:公共CThreadImpllt; CWorkerThreadgt;{市民: 运行的DWORD() {
; / /做一些有用的东西... ... 返回0; }};/ // /在一些其他的功能,那就是从你的主线程调用:CWorkerThread * PTHREAD =新CWorkerThread;
运行的返回值是线程的退出代码,就像在标准的Win32 ThreadProc。
如果您创建了一个CWorkerThread实例,它会立即开始投放。如果你想启动它后,你可以传递CREATE_SUSPENDED CThreadImpl的构造函数,调用resume后。
注意,在创建线程的构造的运行,所以线程初始化一些可能被转移到运行方法。
ExampleClass的CWorkerThread:公共CThreadImpllt; CWorkerThreadgt;{
CWorkerThread() CThreadImpllt; CWorkerThreadgt;(CREATE_SUSPENDED) {} 布尔初始化()
{
/ /执行初始化。 返回TRUE; }
0; 运行的DWORD() { 如果(!初始化())
60; 返回1; / /做一些有用的东西... ...
60; 返回0; }};/ // /在一些其他的功能,那就是从你的主线程调用:CWorkerThread * PTHREAD =新CWorkerThread;PTHREAD - GT;个人简历();GUI线程的执行情况
类CGuiThreadImpl使用WTL类CMessageLoop管理一个消息循环。然而,由于CAppModule想了解的过程中所有CMessageLoops,这意味着你必须在构造函数传递到您的CAppModule实例的指针。
为了实现一个GUI线程,从CGuiThreadImpl派生类(可选)重写以下方法:BOOL InitializeThread()来执行线程初始化。举例来说,这是创建窗口的好地方。返回FALSE停止线程。无效CleanupThread(DWORD)来执行清理任务。 DWORD参数是消息循环的退出代码。处理消息
你也可以添加消息映射到你的线程类使用的标准宏,BEGIN_MSG_MAP。然而,这些被称为不是针对一个窗口,即hWnd参数为NULL的消息。
记住,你可以访问的线程的消息循环使用CAppModule:GetMessageLoop(),这样你就可以,例如,安装额外的CMessageFilters。要做到这一点的地方,将InitializeThread和CleanupThread方法。范例
下面的例子显示了一个简单的GUI线程类创建一个计时器和响应WM_TIMER消息#quot;。Thread.hquot;类CTimerThread:公共CGuiThreadImpllt; CTimerThreadgt;{ BEGIN_MSG_MAP(CTimerThread) &
#160; MESSAGE_HANDLER(WM_TIMER消息,的OnTimer) END_MSG_MAP()私人: UINT_PTR m_nTimerId;市民: CTimerThread(CAppModule * pModule) CGuiThreadImpllt; CTimerThreadgt;(pModule) {} 布尔InitializeThread() { &
#160;m_nTimerId =::SetTimer的(NULL,0,1000,NULL);
;返回(m_nTimerId = 0); } 无效CleanupThread(DWORD)
160; { ::KillTimer(NULL,m_nTimerId); } LRESULT的OnTimer(UINT,WPARAM,LPARAM,BOOLamp;) {
0;::的MessageBeep(MB_ICONASTERISK); 返回0; }};
的"计时器线程"已被创建并停止从主线程:类CMainFrame:... ...{ CTimerThread * m_pTimerThread; / / ...
LRESULT的OnCreate(LPCREATESTRUCT) { / / ... m_pTimerThread =新CTimerThread(AMP; _Module);
; / / ... } 无效OnDestroy() { / / ... g_pTimerThread - GT;调用PostQuitMessage();
60; g_pTimerThread - GT的join(); 删除g_pTimerThread;
160; / / ... }};使用类
所有的线程类都包含在一个头文件,Thread.h,您可以使用在文章开始给出的链接下载。为了方便的类,你只需要在您的项目Thread.h。
如果你想在ATL的但并非WTL的项目中使用的类,您将需要从代码中删除所有的GUI线程相关的章节。其他类(CThreadT和CThreadImpl)的工作以及与"纯"的ATL。结论
使用本文中介绍的类的集合,它是有可能实现一个更清洁,更面向对象的多线程应用程序的设计。其他ATL / WTL的类中发现一个类似模板的设计使得它易于理解和整合。修订历史2006年6月30日原来的文章。2006年6月31日CThreadT:现在调用_beginthreadex(上_ATL_MIN_CRT)如果可能的话。添加方法CThreadT::退出。