微软的公寓类比(STA、MTA):需要帮助理解它
我已经阅读了很多有关 Microsoft 线程公寓模型的内容,但在可视化它时仍然遇到了一些困难。
微软用住在公寓里的生物来比喻。因此,对于 STA,请考虑以下内容(我知道这有点愚蠢)。
假设线程 = 人,COMObject = 细菌。人住在公寓里,细菌就生活在人体内。因此,在 STA-Land 中,线程存在于 STA 中,而 COMObject 存在于线程内部,因此为了与 COMObject 进行交互,必须通过在 COMObject 的线程上运行代码来实现。
假设线程 = person 并且 COMObject = cat。人住在公寓里,猫也和人一起住在公寓里。 SO 在 STA-Land 中,线程和 COMObject 处于同一层次结构级别。
Q1.上述哪个类比是正确的,或者如果两者都不正确,您会如何描述 STA?
Q2。您会如何描述 MTA?
I've read lots about the Microsoft's threaded apartment model, but I'm still having a little trouble visualizing it.
Microsoft uses the analogy of living things living in an apartment. So, for STA, consider the following (I know it's a little silly).
Assume thread = person and COMObject = bacteria. The person lives in the apartment, and the bacteria lives inside the person. So in STA-Land, a thread lives in the STA and the COMObject lives inside the thread, so in order to interact with the COMObject, one must do so by running code on the COMObject's thread.
Assume thread = person and COMObject = cat. The person lives in the apartment, and the cat lives in the apartment with the person. SO in STA-Land, the thread and the COMObject at the same hierarchical level.
Q1. Which analogy above is correct, or if neither are correct, how would you describe the STA?
Q2. How would you describe the MTA?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我不喜欢这些类比。他们很困惑。
你创建了一个公寓。
如果它是一个 STA,则该单元中只有一个线程,因此该单元中的所有对象都将在该单个线程上执行(因此该单元中的对象不会并发执行)
如果它是一个 MTA,则可以该公寓中有多个线程。因此,如果需要,MTA 中的对象需要显式地实现同步。
一个物体住在一间公寓里。同一个公寓中可以有多个对象。
这里非常好读
I do not like these analogies. They are confusing.
You create an apartment.
If it is an STA there will be only one thread in the apartment so all the objects in that apartment will be executed on that single thread (so there is no concurrent execution in the objects in that apartment)
If it is an MTA there can be multiple threads in that apartment. So the objects in the MTA need to implement the synchronization explicitly if needed.
An object lives in one apartment. There can be multiple objects in the same apartment.
A very good read here
这不是一个伟大的术语。它实际上描述了线程行为。线程告诉 COM 它在 CoInitializeEx() 调用中的行为方式,在 STA 和 MTA 之间进行选择。通过使用 STA,线程承诺它的行为方式适合非线程安全的代码。它做出的硬性承诺是:
使用 MTA 意味着线程可以做任何它想做的事情,并且不会付出任何努力来支持非线程安全的代码。
当创建 COM 对象时,这一点首先重要。这样的对象在注册表中包含一个键,该键描述了它实现的线程安全类型。 ThreadingModel 键。到目前为止,该键最常见的值是“Apartment”(或缺失),告诉 COM 它根本不支持线程,并且对该对象的任何调用都必须从同一线程进行。
如果创建此类对象的线程位于 STA 中,那么一切都会很顺利。毕竟,线程承诺支持单线程对象。如果线程位于 MTA 中,则存在问题,该线程表示它不支持线程安全,但仍然创建了一个非线程安全的对象。 COM 介入创建一个新线程,一个可以支持非线程安全代码的 STA 线程。代码获取对象的代理。对对象进行的任何调用都会通过该代理。代理代码拦截调用并使其在创建的 STA 线程上运行,从而确保调用以线程安全的方式进行。
正如您可以想象的那样,代理完成的工作并不便宜。它涉及两个线程上下文切换,并且必须从函数参数构造堆栈帧才能进行调用。它还必须等待,直到线程准备好执行调用。这称为编组,它比进行不需要编组的调用慢 3 个数量级。这也许也解释了 STA 线程具有上面列出的这两个要求的原因。它不能阻塞,因为只要它阻塞,就无法进行编组调用,并且很可能导致死锁。它必须泵送一个消息循环,该循环使得将调用注入另一个线程成为可能。
因此,让线程加入 MTA 对您来说编程很容易。但对性能来说却是致命的。 STA高效。
It is not a great term. It actually describes thread behavior. A thread tells COM how it behaves in the CoInitializeEx() call, selecting between STA and MTA. By using STA, the thread promises that it behaves in a manner that suitable for code that is not thread-safe. The hard promises it makes are:
Using MTA means a thread can do whatever it wants and does not make any effort to support code that is not thread-safe.
This matters first when a COM object gets created. Such an object contains a key in the registry that describes what kind of thread-safety it implements. The ThreadingModel key. By far the most common value for this key is "Apartment" (or is missing), telling COM that it doesn't support threading at all and that any calls on the object must be made from the same thread.
If the thread that creates such an object is in an STA then everything is happy. After all, the thread promised to support single threaded objects. If the thread is in the MTA then there's a problem, the thread said it didn't support thread-safety but still created an object that isn't thread-safe. COM steps in an creates a new thread, an STA thread that can support code that isn't thread safe. The code gets a proxy to the object. Any calls made on the object go through that proxy. The proxy code intercepts the call and makes it run on the STA thread that was created, thus ensuring the call is made in a thread-safe way.
As you can imagine, the job done by the proxy isn't cheap. It involves two thread context switches and a stack frame must be constructed from the function arguments to make the call. It must also wait until the thread is ready to execute the call. This is called marshaling, it is an easy 3 orders of magnitude slower than making a call that doesn't have to be marshaled. This perhaps also explains the reason an STA thread has those two requirements listed above. It cannot block because as long as it blocks that marshaled call cannot be made and makes deadlock very likely. And it must pump a message loop, that loop is what makes injecting a call into another thread possible.
So making a thread join the MTA is easy programming for you. But deadly to performance. An STA is efficient.