同样的代码,为什么新java创建一个新线程的线程有什么没有打印"I am ..",一个打印了,如图

如何建立一个健康的多线程程序-关于多线程和COM和多线程工具,残破的链接在网页中查找的问题_线程,进程及IPC_编程通用_或代码
| 文章 >> 编程通用 >> 线程,进程及IPC
如何建立一个健康的多线程程序-关于多线程和COM和多线程工具,残破的链接在网页中查找的问题
{S0} {S1}简介BlackSabbath这是什么应用程序做的呢?此应用程序需要URL和爬行到指定的深度,发现断开的链接,在网页。这意味着如果深度为2,该工具将打开所有的家长的联系页,并分析其整个子链接在一个子链接。可以很网页制作有助于找到不正确,移动,损坏的链接。有一个事实我要承认的是CHTTPThread短期算法部分:OpenNewLinkandGetData(),这就决定了如果连结被打破是非常原始的。它发现大量破碎的链接,虽然他们都没有,原因父目录协会不正确的。我肯定可以使用从您一些HTML帮助大师确切,并没有时间去做。应用是真正意带出线程和COM的几个方面,以及如何创建一个多线程COM客户端项目有效。架构去如下。我们有两个工作队列。 CThreadSafePtrArray arrLinksDataG,这是一个数组
链接,我们来分析一下。 这是一个HTML数组CThreadSafePtrArray arrHTMLDataG
页面的链接进行分析的数据。
有两个线程阵列 CThreadSafePtrArray HTTPThreadsG是一个线程数组,
会做HTTP交易网页的HTML。的链接
获得arrLinksDataG和由此产生的HTML的,如果有的话会
添加到arrHTMLDataG。如果一个环节被打破,它被添加
显示以及一个XML BlackSabbath.xml文件。任何线程都可以
0;信号使用一个成员变量杀事件,hKillEventM被杀害。 &#16
否则该线程在启动时的最大空闲时间杀死&
有没有工作是由空arrLinksDataG表示。 CThreadSafePtrArray HTMLParserThreadsG是一个数组
从arrHTMLDataG会做HTML的HTML分析和迭代的线程
通过链接,将它们添加到arrLinksDataG。任何线程都可以被信号
使用一个成员变量杀事件hKillEventM被杀害。否则,
线程杀死自己最大空闲时间"开头的时候没有
工作空arrHTMLDataG表示。有一个工作线程,这将作为线程管理。主要在工作​​开始的应用程序线程创建这个线程。该功能utils.cpp showBusy()要分析的URL将被写入数据链接数组之前调用showBusy()。线程创建工程的逻辑,如果工作量超过两次特别线程的数量,如果我们还没有达到线程所允许的最大限额,然后创建一个新线程。线程管理器功能utils.cpp checkBusy()。创建线程管理线程调用utils.cpp checkLoadAndCreateThreadIfNeeded(经理)此功能将创建第一个HTTP线程。工作量是衡量在工作​​队列中的项目计数。新创建的线程将被添加到各自线程数组。线程管理器是在以下方式中丧生。 当用户请求中止操作从GUI和 &#16
主线程启动的所有线程的终止。 自空闲计数时,在左侧没有工作
链接或HTML数据数组有没有工作线程。创建线程安全的MFC类下面是一个创建一个线程安全的MFC派生类的的例子。 MFC类不是线程安全的。它可以很容易地实现派生出一个通用类它和揭露你计划使用的方法。 N.B使用protected或private访问修饰符,除非你计划公开所有方法暴露的基类。否则,它会创造一个unsuspicious问题客户端使用从基类不是线程安全函数。class CThreadSafePtrArray : protected CPtrArray
CRITICAL_SECTION myLockM;
CThreadSafePtrArray();
CThreadSafePtrArray();
void Add(LPVOID newElementA);
LPVOID GetAt(int iIndexA);
int GetSize();
void Lock(){EnterCriticalSection(&myLockM);}
void UnLock(){LeaveCriticalSection(&myLockM);}
LPVOID RemoveHead();
LPVOID RemoveAt(int iIndex);
CThreadSafePtrArray::CThreadSafePtrArray()
InitializeCriticalSection(&myLockM);
CThreadSafePtrArray:: CThreadSafePtrArray()
DeleteCriticalSection(&myLockM);
LPVOID CThreadSafePtrArray::RemoveHead()
FUNCENTRY(&CThreadSafePtrArray::RemoveHead&);
EnterCriticalSection(&myLockM);
LPVOID pRet = CThreadSafePtrArray::RemoveAt(0);
LeaveCriticalSection(&myLockM);
FUNCRETURN(pRet);
LPVOID CThreadSafePtrArray::RemoveAt(int iIndex)
FUNCENTRY(&CThreadSafePtrArray::RemoveAt&);
LPVOID pRet = NULL;
EnterCriticalSection(&myLockM);
if( (iIndex & CPtrArray::GetSize()) &&
(iIndex &= 0))
pRet = CPtrArray::GetAt(iIndex);
CPtrArray::RemoveAt(iIndex);
LeaveCriticalSection(&myLockM);
FUNCRETURN(pRet);
}你可以看到额外的只有几行,一开始在最后。 EnterCriticalSection的(AMP; myLockM),LeaveCriticalSection(AMP; myLockM)。 EnterCriticalSection的我们的阵列上获得锁独特的访问和试图访问的所有其他线程将等到当前线程LeaveCriticalSection。这种方法有其优势比使用传统CPtrArray和同步对象,以确保它。 重用 提供一个方法来自动锁定一贯
每当基础数据的使用和减少代码量
需要相同。&#
160;提供显式锁定/解锁时的功能
下一个锁块的线程安全的操作。将是一个什么情况,使用显式锁定/解锁?比如我调用GetSize()并开始越来越元素逐一阵列经营。这是不将被犹太教。让我们来看看一些代码。说我在循环上午线程,线程2得到控制和删除数组和线程1经营上的最后一个元素。这将导致访问违反。但下面的代码片使用锁定/解锁将保持强劲。{C}从同一个线程锁定两次试图收购可能在这里打扰你,反过来说,一些成员函数调用其他成员函数。所有这些锁定和解锁。这将如何工作。为了避免CEvent以外的所有同步对象死锁将允许锁,如果一个线程已经拥有锁。 CEvent不过,留在国但因为它的总理使用的是作为一个信号的对象。因此,上述片代码将被罚款,虽然它看起来像RemoveHead()将获得锁两次。只要你需要锁定资源在多线程的一个重要原则是锁定资源最低数量的指令,您可以。我可以证明使用情况CThreadSafePtrArray隐式锁使用。看看下面的代码。CThreadSafePtrArray HTTPThreadsG;
CThreadSafePtrArray HTMLParserThreadsG;
CThreadSafePtrArray arrLinksDataG;
CThreadSafePtrArray arrHTMLDataG;
if( (0 & HTTPThreadsG.GetSize())
(0 & HTMLParserThreadsG.GetSize()
(0 & arrLinksDataG.GetSize())
(0 & arrHTMLDataG.GetSize()))
}每个变量被锁定和数组的大小确定后公布。无两种资源都锁定在同一时间。如果我们在使用MFC数据类型通常会锁定所有这些一次。代码如下EnterCriticalSection(HTTPThreadsLockG);
EnterCriticalSection(HTMLParserThreadsLockG);
EnterCriticalSection(arrLinksDataLockG);
EnterCriticalSection(arrHTMLDataLockG);这将导致举行一次,直到最终所有资源上述条件如果。现在,如果你仔细看到说的变量,所有除主线程的线程上运行上述变量和线程管理的需要做上述条件来确定的工作负荷。这将采取的主要性能损失。说,如果发生线程切换线程管理如果条件,没有其他线程将能够完成其工作和将要最后切换回线程管理和完成。这是一个努力说服你总是创建线程安全的数据类型类。声明为C风格的工作线程的线程局部变量如果我们想创建由几个功能共享的变量但工作线程,每个线程有一个独特的价值,我们应该使用_declspec(线程)静态的。这是必要的,只是普通的C风格的工人实施线程。使用C风格的CWinThread派生类实现这个成员变量和成员函数访问这些变量,当然每个线程有一个对象。我会告诉我的应用程序文件的一个例子utils.cpp和utils.h。有没有真正需要使用此我只有一个线程管理线程,目的是为了说明使用。_declspec(thread) static UINT lIdleCount = 0;
BOOL checkIdleMax()
BOOL bIdleMax = false;
if(MAXIDLECOUNT &= lIdleCount)
bIdleMax = true;
return bIdleM
void incrementIdle()
ASSERT(MAXIDLECOUNT & lIdleCount);
lIdleCount++;
void clearIdle()
lIdleCount = 0;
}应用多线程项目的配置文件 =&1.0& =&UTF-8&
&ApplicationConfig&
&AppLogging&
&BrokenLinksXMLFileName&
C:\MyProjects\BlackSabbath\BlackSabbath.xml
&/BrokenLinksXMLFileName&
&BrokenLinksXMLSchemaFileName&BlackSabbathSchema.xml
&/BrokenLinksXMLSchemaFileName&
&BrokenLinksXMLXSLTFileName&BlackSabbath.xsl
&/BrokenLinksXMLXSLTFileName&
&LogFileName&
C:\MyProjects\BlackSabbath\BlackSabbath.log
&/LogFileName&
&CurrentLoggingLevel&1&/CurrentLoggingLevel&
&/AppLogging&
&AppLogging&
&BrokenLinksXMLFileName&
C:\MyProjects\BlackSabbath\BlackSabbath.xml
&/BrokenLinksXMLFileName&
&BrokenLinksXMLSchemaFileName&BlackSabbathSchema.xml
&/BrokenLinksXMLSchemaFileName&
&BrokenLinksXMLXSLTFileName&BlackSabbath.xsl
&/BrokenLinksXMLXSLTFileName&
&LogFileName&
C:\MyProjects\BlackSabbath\BlackSabbath.log
&/LogFileName&
&CurrentLoggingLevel&1
&/CurrentLoggingLevel&
&/AppLogging&
&/Release&
&/ApplicationConfig&上面说的文件是BlackSabbathConfig.xml。它配置设置调试和发布版本。现在的任务是写一个读者类,线程安全访问的配置值。执行有关线程安全是像以前一样使用同步对象相同。类名是CAppConfigReader,它是一个单独的类,这要创建每个应用程序发布一次。应与第一的getInstance调用配置文件的名称。
CAppConfigReader* pConfig =
CAppConfigReader::GetInstance(
&C:\\MyProjects\\BlackSabbath\\BlackSabbathConfig.xml&);
if(NULL != pConfig)
csLogFileName = pConfig-&GetValue(
CString(&/AppLogging/LogFileName&));
}每个后续的调用不应该提供的文件名,因为它会导致重新打开和加载的文件或更改文件。究其原因,是因为实施是单身,有将只有一个,只有一个应用程序配置文件。如果需要更多的配置文件读取,请更改从单身到正常的创建实施。
CAppConfigReader* pConfig = CAppConfigReader::GetInstance();
if(NULL != pConfig)
csLogLevel = pConfig-&GetValue(
(&/AppLogging/CurrentLoggingLevel&));
logLevelM = (eLoggingLevel)atoi(csLogLevel);
} 当你说/ AppLogging / LogFileName pConfig - GT的GetValue,功能前缀调试或作为构建的发行和内部/ /调试/ AppLogging / LogFileName或/ /释放/ AppLogging / LogFileName。多线程项目的日志文件一个多线程的主要调试/故障排除工具项目是一个函数入口/出口和诊断的目的,数据的日志文件记录广告错误记录。日志线程为此为安全多个线程可以同时访问日志文件。我有情侣的便于使用的宏。我将说明这些宏的用法例子。他们创造一个文本文件,在申请中提到的的路径配置文件BlackSabbathConfig.xml。应用程序启动时的日志对​​象要创建如下 CLogFile:创建();,当应用程序退出的日志对象已被删除如下。 CLogFile:推出();宏宣布LoggingAPI.h和用法如下。
FUNCENTRY用途:FUNCENTRY("CHTTPThread:InitI);在开始使用FN。 FUNCEND用途:FUNCEND;使用FN结束。 FUNCRETURN用途:FUNCRETURN(FALSE);使用结束按fn。 INFOLOG用法:INFOLOG((";主题ID:%d个\,PTHREAD - GT; m_nThreadID)); INFOLOG((线程创建成功\));注意:使用像CString是:格式()论据在()。该消息的前缀与数据: THREADDATALOG用途:作为INFOLOG相同,只是不同的名称清晰度。 LOGWARNING用途:作为INFOLOG相同。然而消息前缀警告: LOGERROR用途:作为INFOLOG相同。然而消息前缀错误:
LOGFATALERROR用途:作为INFOLOG相同。然而消息前缀致命错误:设置错误日志记录级别使用配置文件,您可以设置错误日志记录的水平。关键在配置文件如下: LT; CurrentLoggingL 1LT; / CurrentLoggingL值的平均值以下 功能水平= 0 INFO级别= 1 警告级别= 2 错误级别= 3 致命等级= 4 CurrentLoggingLevel = 1表示在配置1以上的所有日志消息和1个将被记录。这意味着功能级别的日志记录将被忽略。日志条目示例 14:09:13.219主题(1540年)进入CMRUCombo:AddToMRUList文件(C:\ myprojects \ blacksabbath \ mrucombo.cpp)线(56) 14:09:13.219主题(1540)退出CMRUCombo:AddToMRUList文件(C:\ myprojects \ blacksabbath \ mrucombo.cpp)线(80)上述手段执行正常功能。 14:24:21.305主题(1516)异常退出CBlackSabbathApp:InitInstance中文件(C:\ myprojects \ blacksabbath \ blacksabbath.cpp)这是不愉快的。可以有两个原因。 你忘了终止与FUNCEND功能或
FUNCRETURN。 有未处理的异常和失去控制
从功能上。这表明日志记录更多的优势,检测
例外。注:不过,伐木是根据你的自由裁量权的是什么你赎回重要的,哪些是你不。类型的功能,以避免记录是UpdateCommandUI,PreTranslateMsg,OnPaint中,OnDraw中,的OnTimer,CARRAY:GetAt派生的处理程序。原因是,他们通常被称为功能和爆炸您的日志文件,并使它的可读性。COM接口和线程模型线程的初始化的COM的COM每个线程初始化,否则所有的COM调用将返回RPC_E_THREAD_NOT_INIT。可以做一次,如果初始化与不同的线程模型CoInitialize的()或重新初始化的CoInitializeEx()将返回RPC_E_CHANGED_MODE。另外一个显着的一点是,初始化像一个正常的COM接口,它的引用计数。所以你将不得不CoUnitialize()作为初始化多次。如果不这样做,它不会是一个主要的问题,因为它们是底层的COM库DLL的引用。从DLL初始化创造一个DLL中的COM承担了一件事 - DLL的客户端将初始化COM,DLL上运行,线程模型。否则在上一节的说明初始化错误会出现 - 重复使用不同的线程模型初始化或重新初始化。CoUnitialize()和应用程序禁售的原因是CoUnitialize()在内部创建一个模式消息循环,并等待无限期,直到所有的COM消息被清除。这可以创建问题在DLL中的COM组件卸载时不检查,如果是准备卸载。它一般发生时动态加载的DLL承载一个COM接口。 DLL会从一个应用程序运行和使用应用程序的消息队列同步的目的,如果模型是单元线程。请不宜访问动态加载的DLL的COM接口。我没有一个更好的解决方案。但如果你不小心不管怎么说,删除CoUnitialize()。编组站跨线程 COM接口是线程亲和性。这是什么语句是什么意思? COM接口属于线程创建和生活,并与他们死亡。什么如果其他线程需要访问这个接口。父马歇尔这个接口给其他线程。如果我们只是用这个,会发生什么事接口从一个线程安全的全局变量?一切都会好,但是当我们访问这个接口的方法或属性,COM将抛出RPC_E_WRONG_THREAD错误。一个可用的标准功能编组的目的是CoMarshalThreadInterfaceInStream()和CoGetInterfaceAndReleaseStream()。这些都是老的功能;我们有一个简单的方法要做到这一点。 IGlobalInterfaceTable简称为GIT的。此接口内部实现线程之间的编组。下面是用法CBrokenLinksFile,这是一个XML文件作家。使用多个线程CBrokenLinksFile写在XML格式到磁盘损坏的链接。声明和创建GIT下面的代码是线程管理器线程运行。#include &atlbase.h&
CComGITPtr&MSXML2::IXMLDOMDocument2& CBrokenLinksFile::xmlDocGITM;
MSXML2::IXMLDOMDocument2Ptr pXMLDoc = NULL;
HRESULT hrDoc = CreateInstance(pXMLDoc,CLSID_DOMDocument2);
if(SUCCEEDED(hrDoc))
xmlDocGITM = pXMLDoc.GetInterfacePtr();
}从Git访问接口
下面的代码是由CHTTPThreadMSXML2::IXMLDOMDocument2* pXMLDoc = NULL;
HRESULT hrGITAccess = xmlDocGITM.CopyTo(&pXMLDoc);
if(SUCCEEDED(hrGITAccess))
}从Git的撤消接口下面的代码是线程管理器线程运行。
xmlDocGITM.Revoke();注意:只有线程创建/注册界面可以撤销它。这意味着创建的线程保持活着,直到撤销。是的,是真实的。谁创造了它的线程死亡时,接口也变得无效。我的COM接口和死锁线程执行?这是一个非常有趣的方面,你平时忽视。在这问题往往在于回答为什么有时您的应用程序死锁。 "答案是,它取决于你的线程模型。让我们讨论的线程模型 - 公寓和自由线程。如何确定一个组件的线程模型你会看在HKEY_CLASSES_ROOT / CLSID的类ID或名称的组成部分。DLL或。exe。这里是一个什么WebBrowser2组件的注册说,在Regedit中,组件的二进制shdocvw.dll中。在HKEY_CLASSES_ROOT / CLSID的展望 {0A89A860 - D7B1 - 11CE - 8350 - } InProvServer32默认 - REG_EXPAND_SZ - %SYSTEMROOT%\ SYSTEM32 \ shdocvw.dll中的ThreadingModel - 公寓COM对象的创建失败和不正确的线程模型仔细看上面的注册表项。这意味着可以WebBrowser2控制从公寓初始化的线程创建。我必须找到它的硬盘方法和上面介绍的是我发现它的线程模型的方式。 "问题,我面对的是,我InitDialog()FN将在CDialog的失败:CreateDialogControls(FN)。当一个程序员忘记一个常见的​​场景调用OleInitialize(),CoInitialize的的CoInitializeEx(),(COINIT_APARTMENTTHREADED),。但我的观点是CoInitializeEx的(COINIT_MULTITHREADED)的工作来解决这个问题。它会工作组件的注册表表示的ThreadingModel - 免费或两者。这两种手段的对象是创建的所有线程模型下的安全。然而,它是不可能的改变上面说的手动注册表值,并得到它的工作。这将虽然暂时InitDialog()可能导致不可预知的结果取得成功。我会解释。如果线程模型是在注册表中手动更改会发生什么?当接口是在公寓中创建线程,COM函数调用CoInitialize的()或任何相当于创建一个消息循环,并用它来同步COM调用任何COM对象在该线程中创建。呼叫在排队的顺序将被执行。为什么要使用消息队列排队组件的父线程?这将确保只有一个调用将执行在特定的时间并没有使COM对象的线程安全的需要。公寓COM线程模型是实现线程安全的COM组件只是标志着在注册表中的ThreadingModel - 公寓。公寓线程
未能利用多线程的优势,因为调用将有切换到COM接口的父线程,这将可能是一个为每一个线程使用这些接口的开销。因此,对于复杂的COM对象通常支持自由线程。这必然意味着底层的COM实施对象是线程安全的。将COM接口的方法调用在调用线程中执行。在一个多线程的项目将有为争说COM对象的资源。但不用担心对象线程安全的。所以,如果你在注册表中更改线程模型,并作了自由线程单元线程组件,并用它在一个多线程项目时,会发生什么?如果有线程争用任何共享COM对象中的资源,结果将是不可预知的,因为组件不是线程安全的设计。死锁在公寓线程的线程创建的COM对象将执行特定的接口调用。说线程1创建Component1是单元线程。线程1调用一个函数,它必须等待线程2完成。线程完成它需要Component1方法/属性呼叫。这将导致死锁,调用对线程只能执行。这两个线程将等待对方。什么是可能的解决? 初始化线程1的CoInitializeEx(COINIT_MULTITHREADED)。这
可以做到的,只有在组件允许这种线程模型。其他步骤2 创建另一个线程上的接口没有潜在
死锁条件。也看到这样的情况下,你可以改变主线程模型在文件BlackSabbathDlg.cpp中的线程单元线程。点击抓取按钮。一旦开始写点击链接停止抓取按钮。 "应用程序会死锁。这是因为主线程试图杀死所有线程通过调用ClearBusy()。 xmlDoc中的对象是由主线程创建。主线程将等待CHTTPThread CHTTPThread处理:串连()clearBusy()调用的一部分。同时CHTTPThread将尝试访问xmlDoc中的对象写的brokenlink。这个函数上运行主线程,它是一个死的锁,线程互相等待的同时时间。如何检测死锁和应用程序锁定/无限循环 {S2} Microsoft分发免费WinDbg中,这是一个调试工具广泛的功能。。 (Microsoft知识库文章 - 311503)。它可以下载从以下位置/whdc/ddk/debugging/。无论您可以使用Microsoft符号服务器或以上的文章给解释,添加符号路径,或者你可以下载的符号文件,并安装它在您的硬盘驱动器。这里是如何获得硬盘上的NT符号文件 - Microsoft知识库文章 - 148659。启动WinDbg和选择文件菜单选择符号文件路径....包括您的设置符号文件的路径应用PDB或DBG文件的目录。由通常的SYSTEM32目录包含许多DLL像MFC42D.DLL的符号,msvcrtd.dll等选择刷新复选框,这将重新加载新的符号文件。 Q121366:INFO:PDB和DBG文件 - 它们是什么以及它们如何工作介绍有关符号文件。另外,请在微软找到有趣的文章调试工具知识库文章。为了使生成调试信息/符号(。pdb文件)发布/调试的Visual C + + 6.0开发环境的建立,按照下列步骤:在项目菜单上,单击设置。单击"Win32 Release配置。在C / C + +选项卡,单击"常规",然后设置如下:设置优化最大限度地提高速度或最小化大小。设置调试信息的程序数据库。在"链接"选项卡,单击"常规",然后设置以下内容:确保您单击以选中生成调试信息。请确保您清除链接逐步检查框。直接编辑项目选项,然后添加/ OPT:REF,ICF。要使用微软格式的调试信息,选择微软格式或链接/调试调试信息下的两个选项按钮。如果生成调试信息"复选框没有被选中,这个选择是不可用。在命令行,如果/调试被指定,默认的类型是/ DEBUGTYPE:简历,如果/调试不指定/ DEBUGTYPE被忽略。现在,当您的应用程序挂起你要运行的应用程序称为UserDump.exe。这将创建一个转储文件捕获的状态应用。 UserDump.exe是一个独立的可执行文件,可以操作标准的Windows安装。请参阅下面的文章来看看如何如何获得一个转储文件使用Userdump.exe捕获信息存储的国家。让我们假设您的转储文件被命名为。现在开始从你的程序的WinDbg。从文件菜单选择"打开崩溃转储",定位到上述文件并打开它从视图中,选择"进程"和线程和调用堆栈。这会告诉你,你的程序是,如果在你双击调用堆栈上线,将打开相应的代码文件。这才会发生,如果你设立正确的符号。打破僵局检测,选择菜单项View命令,命令窗口会。从命令行,键入!僵局,如果有的话,它会报告死锁。如果不检查每个线程的调用堆栈是你最好的选择,应用程序可能会在一个无限循环。 一些有用的命令在命令行上键入 重载 - 重整符号 锁 - 报告所有的锁定同步对象 !僵局 - 检测死锁 过程中时间的详细信息,时间 -
sysmpath - 设置符号文件路径 !过程 - 进程信息 线程LT线程ID - 线程的信息。开去
; 帮助找到更多。
关于作者:
中国我是一名编程爱好者,谢谢为我们提供一个学习和分享的平台。有什么问题。可以就本内容回复,我看到时。会尽量回复的。
评论会员:
时间:用户界面线程泵的消息。它是在CWinThread实施::运行如果你看看我的实现,它的InitInstance退出。这是一个工作者线程并发的问题,一般都是一个工作线程的问题,不是一个用户界面线程原因 - 有多少个并发的寡妇,你会为用户产卵看到吗?
5,10最大?他们是否需要线程
这里去如何管理用户界面线程。它需要得到控制,运行()
和运行执行以下行泵WM_QUIT
NBSP的消息并退出;
而(的PeekMessage(安培;味精,HWND,空,空,PM_REMOVE))
(msg.message == WM_QUIT)
现在我修改
BOOL CHTMLParserThread:的InitInstance() {
FUNCENTRY( "CHTMLParserThread::InitInstance中");
FUNCRETURN(TRUE)
BOOL CHTMLParserThread:运行() { - ;
FUNCENTRY("CHTMLParserThread::运行");
/ /初始化为自由线程虽然
/ /右现在不打紧,但我们
/ /同步自己,我们不
/ /需要,因为这将公寓线程
的CoInitializeEx(0,COINIT_MULTITHREADED);
HRESULT的hrDoc的CreateInstance(pDocM,CLSID_HTMLDocument)
/ /如果我们有一个指针添加到全局接口表
(SUCCEEDED(hrDoc)) - ;
/ /这是我们的FN运行直至死亡
ParseLinks()
/ /我们装箱HTML文档对象解析的目的 NBSP失败;
NBSP - ; LOGFATALERROR(("错误创建HTML文档COM对象"));{ BR}
(_com_erroramp E)
ShowComError(E )
赶上(...){ BR}
ShowGetLastError()
/ /我们完成后,取消初始化COM
CoUninitialize();
FUNCRETURN(TRUE);
{BR }****** ************{ BR}主要变化在这里{BR }******************{ BR}
CHTMLParserThread: ParseLinks()
删除以下行
而(WAIT_TIMEOUT ==::WaitForSingleObject的(hKillEventM,0)) {
(的PeekMessage(安培;味精HWND,NULL,NULL,PM_REMOVE))
(msg.message == WM_QUIT)
CHTMLParserThread::ParseLinks() {
FUNCENTRY("CHTMLParserThread:ParseLinks");
而(的PeekMessage(安培;味精,HWND,NULL, NULL,PM_REMOVE))
如果(msg.message == WM_QUIT)
TranslateMessage()
NBSP ; - ;
DispatchMessage函数(); NBSP
/ /休息你把逻辑,如果需要的话
活也让别人活的循环处理{ BR}
<科类="ForumMod"GT;修改日(星期一),日1:32 AM /评论会员:
时间:我用你的代码的一部分监测过程中,我有一个方法来显示和隐藏端口监视器"窗口。 问题是,当我关闭窗口,并尝试退出线程。
我没有和您一样的
(NULL!= pMonitorThread){
pMonitorThread -> PostThreadMessage(WM_QUIT,0,0); }
但下一次我调用的函数指针,显示窗口{&#8203;&#8203;BR}pMonitorThread不为NULL,因此线程不会被创建和消息不会成为显示在监视器窗口
/ /创建记录器线程(pMonitorThread == NULL){
pMonitorThread =(CMonitorThread *)AfxBeginThread(RUNTIME_CLASS(CMonitorThread))}
所以我尝试解决此初始化后调用退出线程的指针
(NULL!= pMonitorThread){&#1
pMonitorThread -> PostThreadMessage(WM_QUIT,0,0);
pMonitorThread = NULL; }
但有时仍然是程序发布消息,所以崩溃,所以我尝试等待的线程结束
(pMonitorThread!= NULL){
pMonitorThread -> PostThreadMessage(WM_QUIT,0,0);
WaitForSingleObject的(pMonitorThread> m_hThread,无限);
pMonitorThread = NULL; }
但有时事件从未发生过,一个我计划在那里逗留无限。
我怎样才能正确地结束线程或我在哪里可以正确初始化用户线程的指针?
感谢您的帮助的意见。
Anonimous 评论会员:
时间:对不起已故的答复..我没有看到你的问题,在我的收件箱。垃圾邮件.. NBSP
我不知道如果我有帮助
我看到的第一个问题是,你试图重用pMonitorThread。一旦你发送QUIT消息,线程是为你做。如果一个线程挂起,这是一个不同的问题fix.So设置指针为NULL,然后重新创建一个线程指针每次你想显示一个新的窗口
另一种方法,不发送WM_QUIT。对其他线程使用一个隐藏窗口,并保持重用线程和窗口
现在一点要记住。 Windows是线程亲和..这意味着他们有一个与他们的父线程的关系,很难创造有线。它如何适用于你,如果你尝试重用线程
创建一个新的窗口,每次从主线程分配,事情可能无法正常工作了....一个简单的证明GetWindowThreadProcessId()SDK FN
我这里附上链接粘贴到一个重要切亲和力的用户界面对象,第1部分:窗口句柄{BR }------------------------------------ -----------------------------{ BR}不同的对象有不同的线程关联的规则,但是从16位Windows的基本原则
最重要的用户界面元素是当然的窗口。窗口对象具有线程关联。线程创建一个窗口一个窗口有不可分割的关系。非正式的,一说,该线程"拥有"的窗口。消息分派到窗口过程,只有在拥有它的线程,一般来说,一个窗口的修改应只能从拥有它的线程。
&桌面&网页开发&移动开发&数据库&多媒体&编程语言&平台,框架和库&编程通用&图形/设计&开发周期&一般阅读&第三方产品&作者资源&其他
快速解答标签
价值作最多

我要回帖

更多关于 java创建新线程 的文章

 

随机推荐