这不是一个很好的术语。它实际上描述了线程行为。一个线程告诉 COM 它在 CoInitializeEx() 调用中的行为方式,在 STA 和 MTA 之间进行选择。通过使用 STA,线程承诺它的行为方式适合非线程安全的代码。它做出的坚定承诺是:
使用 MTA 意味着线程可以做它想做的任何事情,并且不会做出任何努力来支持非线程安全的代码。
当创建 COM 对象时,这首先很重要。这样的对象在注册表中包含一个键,该键描述了它实现了哪种线程安全。ThreadingModel 键。到目前为止,该键最常见的值是“Apartment”(或缺失),它告诉 COM 它根本不支持线程,并且对对象的任何调用都必须从同一个线程进行。
如果创建这样一个对象的线程在 STA 中,那么一切都很顺利。毕竟,线程承诺支持单线程对象。如果线程在 MTA 中,那么就有问题,线程说它不支持线程安全,但仍然创建了一个不是线程安全的对象。COM 步骤创建一个新线程,一个可以支持非线程安全代码的 STA 线程。代码获取对象的代理。对该对象进行的任何调用都会通过该代理。代理代码拦截调用并使其在创建的 STA 线程上运行,从而确保以线程安全的方式进行调用。
可以想象,代理完成的工作并不便宜。它涉及两个线程上下文切换,并且必须从函数参数构造一个堆栈帧才能进行调用。它还必须等到线程准备好执行调用。这被称为marshaling,它比进行不需要编组的调用要慢 3 个数量级。这也许也解释了 STA 线程具有上面列出的这两个要求的原因。它不能阻塞,因为只要它阻塞了无法进行封送调用并很可能导致死锁。它必须泵送一个消息循环,该循环使得将调用注入另一个线程成为可能。
因此,使线程加入 MTA 对您来说很容易编程。但对性能致命。STA 是有效的。