Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Multithreading 遗留VB6 COM+;DLL调用到本机Win32 DLL--STA的线程问题?_Multithreading_Com_Vb6_Apartments - Fatal编程技术网

Multithreading 遗留VB6 COM+;DLL调用到本机Win32 DLL--STA的线程问题?

Multithreading 遗留VB6 COM+;DLL调用到本机Win32 DLL--STA的线程问题?,multithreading,com,vb6,apartments,Multithreading,Com,Vb6,Apartments,遇到乍一看像机器翻译的问题,但我试图详细了解COM+使用的STA模型 有效地,我有一个用VB6编写的遗留COM+组件,它调用了用C++编写的本地(即,不是COM)Win32 DLL。 由于它有一些间歇性(并且在测试中不可能重现)问题,我添加了一些调试代码以了解发生了什么,并发现当问题发生时,我在文件中交错了日志消息-因此这意味着DLL同时被两个线程调用 现在,日志记录基于一个线程文件,它是基于.gGPIdId()和GeCurrutStudiDeD()的,因此,当调用C++ DLL中的代码时,它同

遇到乍一看像机器翻译的问题,但我试图详细了解COM+使用的STA模型

有效地,我有一个用VB6编写的遗留COM+组件,它调用了用C++编写的本地(即,不是COM)Win32 DLL。 由于它有一些间歇性(并且在测试中不可能重现)问题,我添加了一些调试代码以了解发生了什么,并发现当问题发生时,我在文件中交错了日志消息-因此这意味着DLL同时被两个线程调用

<>现在,日志记录基于一个线程文件,它是基于.gGPIdId()和GeCurrutStudiDeD()的,因此,当调用C++ DLL中的代码时,它同时调用同一线程上的两次。我对STA的理解表明,当COM将对象的各个实例封送到一个线程上时,可能会出现这种情况,挂起并随意恢复执行

不幸的是,我不知道该从这里走到哪里。我读到我应该在DllMain()中调用CoInitialiseEx()来告诉COM这是一个STA DLL,但其他地方说这只对COM DLL有效,不会对本机DLL产生任何影响。唯一的另一种选择是将DLL的部分包装为关键部分,以序列化访问(接受对系统性能的任何影响)

我可以尝试重新编写DLL,但没有共享状态或全局变量-所有内容都在局部变量中,因此理论上每个调用都应该有自己的堆栈,但我想知道STA模型是否基本上对此有一些奇怪的影响,只是在与另一个调用相同的入口点重新进入已加载的DLL。不幸的是,我不知道如何证明或检验这个理论

问题基本上是:

  • 当STA COM+组件调用本机DLL时,STA模型中没有任何内容可供调用 防止活动的“线程”被挂起并控制在DLL调用中间传递到另一个“线程”?
  • CoInitialiseEx()是否是解决此问题的正确方法
  • 如果(1)或(2)都不是“好”的假设,会发生什么

  • 在单元线程COM服务器中,COM类的每个实例都保证由单个线程访问。这意味着实例是线程安全的。但是,可以使用不同的线程同时创建许多实例。现在,就COM服务器而言,您的本机DLL不必做任何特殊的事情。想想每个可执行文件都使用的kernel32.dll,当COM服务器使用它时,它会初始化COM吗


    从DLL的角度来看,您必须确保线程安全,因为不同的实例可以同时调用您。STA不会在本案中保护您。既然你说你没有使用任何全局变量,我只能假设问题出在其他地方,只是碰巧出现在似乎指向COM的情况下。你确定你没有一些普通的C++内存问题吗?< /P> < P>我怀疑你的问题是在调用DLL的某个地方,它向另一个公寓(另一个线程在同一进程中,或者MTA中的对象,或者完全是另一个进程)发出了一个出站的COM调用。COM允许STA线程等待出站调用的结果来接收另一个入站调用,并递归地处理它。它仅适用于相同对象之间正在进行的对话(即A调用B、B调用A、A再次调用B),但如果您向多个客户端发送了接口指针,或者客户端共享了指向另一个客户端的接口指针,则可以接收来自其他对象的调用。通常,将指向单个线程对象的接口指针分发给多个客户端线程是一个坏主意,因为它们只需等待对方。每个线程创建一个辅助对象

    COM不能在任何线程上随意挂起和恢复执行-STA线程上的新传入调用只能通过消息泵到达。当“阻塞”等待响应时,STA线程实际上是在泵送消息,使用消息过滤器(请参阅IMessageFilter)检查是否应该处理消息。但是,消息处理程序不得发出新的传出呼叫-如果发出,COM将返回RPC_E_CANTCALLOUT_InternalCall错误(“在消息筛选器内发出呼叫是非法的。”)

    如果在本机DLL中的任何位置都有消息泵(GetMessage/DispatchMessage),则可能会出现类似的问题。我在VB的接口过程中遇到了一些问题


    CoInitializeX应该只由线程的创建者调用,因为只有他们知道他们的消息泵送行为是什么。如果您尝试在DllMain中调用它,很可能会失败,因为您的本机DLL正在被调用以响应COM调用,因此调用方必须最终已经在线程上调用了CoInitializeEx才能进行调用。对于新创建的线程,在DLL_THREAD_ATTACH通知中执行此操作可能表面上起作用,但如果COM在应泵送时阻塞,则会导致程序故障,反之亦然。

    此问题似乎仅在加载时发生在生产系统上。DLL的代码没有全局变量,只使用局部变量。输出日志文件(根据线程和进程id唯一命名)包含交错输出,这表明它在中间状态下被同一线程调用了两次。在所有其他环境中,代码执行完全正确。1。你到底遇到了什么样的问题?撞车、挂断电话、行为不端?2.您是否直接或间接地创建线程或发送消息?3.当你发现问题时,试着创建一个MIDIDUMP(或完全转储),堆栈跟踪可能有助于在你的DEV C++的舒适性中识别问题。