【问题标题】:Few Questions about Threading, COM+ and STA apartments关于线程、COM+ 和 STA 单元的几个问题
【发布时间】:2011-07-14 09:39:25
【问题描述】:

我有一个创建 10 个线程 + 一个创建任务列表的 Windows 服务。

这 11 个线程中的每一个都通过调用 CoInitialize(nil) 进入 STA。

  1. 任务列表由一个线程创建,另一个线程获取项目,处理它并释放....

a) 其他线程可以使用其他线程创建的对象吗? (这似乎有效,但是..) b) 其他线程可以释放其他线程分配的内存吗? (这似乎行不通...)

我应该以某种方式在线程之间编组指针吗? 还是我至少应该得到该项目,对其进行处理,但让它成为创建它的线程的“所有者”?

  1. 在我的 Windows 服务中,我创建了可用于启动/停止服务(暂停和恢复线程)的功能。

但是,我对实际收集数据并在间隔内执行的线程有疑问。 当线程加载要处理的项目后,它进入睡眠状态 5 分钟。 我怎样才能安全地终止这样的线程?如何中止睡眠状态?

提前感谢您的帮助!

【问题讨论】:

    标签: multithreading delphi com+ sta


    【解决方案1】:

    您可能必须跨线程编组接口。 Here 你可以找到一个 C++ 示例,同一篇文章展示了你可以使用的三种技术(oMarshalInterThreadInterfaceInStream/CoMarshalInterface/Global Interface Table(GIT))。有关它们的更多信息,您可以在 MSDN 中找到。

    要让线程等待但能够在睡眠结束之前终止它,请使用具有适当超时值的 WaitForSingleObject() 以及要等待的 Windows 事件。当函数退出时,它会告诉它是否因为超时或事件已设置而退出。要在达到超时之前退出等待功能,只需设置事件。因此您可以选择是进入另一个等待循环还是退出。

    【讨论】:

    • 从应用程序示例中我读到:“如果您在一个 STA 线程中创建 COM 对象,则不能将接口指针传递给另一个 STA 线程并调用该指针。如果您尝试,您将得到 0x8001010E 或 RPC_E_WRONG_THREAD 的错误 HRESULT(应用程序调用了为不同线程编组的接口)。”这是否意味着只有 com 对象必须被编组?从 TObject 派生的类的常见实例呢?
    • 这取决于您使用什么以及如何创建它。所有与 COM 相关的东西都必须遵守 COM 规则。不受 COM 控制的东西不会。因此,如果您有一个普通的 Delphi 类实例,您可以传递它并在不同的线程中使用它,并使用“经典”并发技术来保护对它们的访问。如果您要使用 COM 对象(并且可能正在使用一些,如果您正在调用 CoInitialize),您必须正确管理它们的接口以在线程之间传递它们。无论如何,请注意内部包装 COM 对象的 Delphi 类(即与 MSXML 一起使用时的 TXMLDocument)
    【解决方案2】:

    要在 STA 线程之间编组 STA 对象指针,请使用 CoMarshallInterThreadInterfaceInStreamCoGetInterfaceAndReleaseStream

    STA 线程必须泵送消息,因为这是 STA 线程使用 COM 的方式,使用 Windows 消息。 IE。您必须调用 GetMessage/TranslateMessage/DispatchMessage。可能您的框架有一个简单的消息泵功能,您可以使用它来执行此操作。

    要中止 5 分钟的睡眠状态,请在更短的时间间隔内进行多次睡眠,并检查“应该退出”标志。在 Service Main 中设置 shouldquit 标志。

    【讨论】:

    • 广告1。我知道存在这种方法,但是我很好奇两个线程之间是否需要它。广告2。我知道这是解决方案,但是因为我一直在尝试执行“等待操作”,而不需要像循环等这样的处理器循环。这就是为什么我很好奇睡眠或其他东西是否可以被编程中断以让线程优雅地完成了它的工作。
    • 是的,两个线程之间是绝对必要的。它将创建一个代理来处理每次调用的线程/锁定问题。此外,STA 线程必须泵送消息,因此您无法睡眠。你应该做一个不睡觉的消息泵。无论如何,消息泵都会休眠。
    • 1.那么为什么 delphi 允许我检索和使用由另一个线程创建的对象呢? 2. 那么这是否意味着,在线程之间传递的对象必须从特定的接口派生。当它被“解组”(使用 CoGetInterfaceAndReleaseStream)时,应该释放对象的实例:在创建它的线程中以及使用 CoGetInterfaceAndReleaseStream 的线程中?
    • 1.如果您遵守规则,COM 将为您做很多事情,但您始终可以选择打破规则。 Delphi 是一种语言,如果你下定决心,它会让你在脚下开枪。 2. 只要您坚持使用 COM 接口,Delphi 就会(可能)为您解决这个问题。 2b。 COM 中的对象是引用计数的。每次为AddRefed 时,都需要为Released 一次。从CoGetInterfaceAndReleaseStream 检索到的代理对象必须从检索它的线程中释放。
    • Delphi 接口对象不依赖于 COM。如果您不使用 COM 的 CoCreateInstance/Ex() 函数创建接口对象的实例,那么您对该对象的线程间访问不受 COM 的封送规则的限制。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-10-07
    • 1970-01-01
    • 2013-07-28
    • 2019-09-15
    • 1970-01-01
    • 2013-12-28
    相关资源
    最近更新 更多