.net 你能解释一下STA和MTA吗?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/127188/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 10:04:03  来源:igfitidea点击:

Could you explain STA and MTA?

.netmultithreadingcomapartments

提问by John

Can you explain STA and MTA in your own words?

你能用自己的话解释一下STA和MTA吗?

Also, what are apartment threads and do they pertain only to COM? If so, why?

另外,什么是单元线程,它们是否仅与 COM 有关?如果是这样,为什么?

采纳答案by Joseph Daigle

The COM threading model is called an "apartment" model, where the execution context of initialized COM objects is associated with either a single thread (Single Thread Apartment) or many threads (Multi Thread Apartment). In this model, a COM object, once initialized in an apartment, is part of that apartment for the duration of its runtime.

COM 线程模型称为“单元”模型,其中初始化的 COM 对象的执行上下文与单个线程(单线程单元)或多个线程(多线程单元)相关联。在此模型中,COM 对象一旦在单元中初始化,在其运行时期间就是该单元的一部分。

The STA model is used for COM objects that are not thread safe. That means they do not handle their own synchronization. A common use of this is a UI component. So if another thread needs to interact with the object (such as pushing a button in a form) then the message is marshalled onto the STA thread. The windows forms message pumping system is an example of this.

STA 模型用于非线程安全的 COM 对象。这意味着它们不处理自己的同步。它的一个常见用途是 UI 组件。因此,如果另一个线程需要与对象交互(例如按下表单中的按钮),则消息将被编组到 STA 线程上。windows窗体消息泵系统就是一个例子。

If the COM object can handle its own synchronization then the MTA model can be used where multiple threads are allowed to interact with the object without marshalled calls.

如果 COM 对象可以处理自己的同步,则可以使用 MTA 模型,其中允许多个线程与对象交互,而无需编组调用。

回答by Mike Dimmick

It's all down to how calls to objects are handled, and how much protection they need. COM objects can ask the runtime to protect them against being called by multiple threads at the same time; those that don't can potentially be called concurrently from different threads, so they have to protect their own data.

这完全取决于如何处理对对象的调用,以及它们需要多少保护。COM 对象可以要求运行时保护它们不被多个线程同时调用;那些没有可能被不同线程并发调用的,所以他们必须保护自己的数据。

In addition, it's also necessary for the runtime to prevent a COM object call from blocking the user interface, if a call is made from a user interface thread.

此外,如果从用户界面线程进行调用,运行时还需要防止 COM 对象调用阻塞用户界面。

An apartmentis a place for objects to live, and they contain one or more threads. The apartment defines what happens when calls are made. Calls to objects in an apartment will be received and processed on any thread in that apartment, with the exception that a call by a thread already in the right apartment is processed by itself (i.e. a direct call to the object).

一个公寓是对象住的地方,它们包含一个或多个线程。公寓定义了拨打电话时会发生什么。对单元中对象的调用将在该单元中的任何线程上接收和处理,但由已在正确单元中的线程调用的调用由自身处理(即对对象的直接调用)。

Threads can be either in a Single-Threaded Apartment (in which case they are the only thread in that apartment) or in a Multi-Threaded Apartment. They specify which when the thread initializes COM for that thread.

线程可以位于单线程单元中(在这种情况下,它们是该单元中的唯一线程)或位于多线程单元中。它们指定线程何时为该线程初始化 COM。

The STA is primarily for compatibility with the user interface, which is tied to a specific thread. An STA receives notifications of calls to process by receiving a window message to a hidden window; when it makes an outbound call, it starts a modal message loop to prevent other window messages being processed. You can specify a message filter to be called, so that your application can respond to other messages.

STA 主要是为了与绑定到特定线程的用户界面兼容。STA通过接收到隐藏窗口的窗口消息来接收调用进程的通知;当它进行出站调用时,它会启动一个模态消息循环以防止处理其他窗口消息。您可以指定要调用的消息过滤器,以便您的应用程序可以响应其他消息。

By contrast all MTA threads share a single MTA for the process. COM may start a new worker thread to handle an incoming call if no threads are available, up to a pool limit. Threads making outbound calls simply block.

相比之下,所有 MTA 线程都为进程共享一个 MTA。如果没有可用线程,COM 可能会启动一个新的工作线程来处理传入调用,直至达到池限制。进行出站调用的线程只是阻塞。

For simplicity we'll consider only objects implemented in DLLs, which advertise in the registry what they support, by setting the ThreadingModelvalue for their class's key. There are four options:

为简单起见,我们将只考虑在 DLL 中实现的对象,这些对象通过设置ThreadingModel它们类的键的值在注册表中公布它们支持的内容。有四个选项:

  • Main thread (ThreadingModelvalue not present). The object is created on the host's main UI thread, and all calls are marshalled to that thread. The class factory will only be called on that thread.
  • Apartment. This indicates that the class can run on any single-threaded-mode thread. If the thread that creates it is an STA thread, the object will run on that thread, otherwise it will be created in the main STA - if no main STA exists, an STA thread will be created for it. (This means MTA threads that create Apartment objects will be marshalling all calls to a different thread.) The class factory can be called concurrently by multiple STA threads so it must protect its internal data against this.
  • Free. This indicates a class designed to run in the MTA. It will always load in the MTA, even if created by an STA thread, which again means the STA thread's calls will be marshalled. This is because a Freeobject is generally written with the expectation that it can block.
  • Both. These classes are flexible and load in whichever apartment they're created from. They must be written to fit both sets of requirements, however: they must protect their internal state against concurrent calls, in case they're loaded in the MTA, but must not block, in case they're loaded in an STA.
  • 主线程(ThreadingModel值不存在)。该对象是在主机的主 UI 线程上创建的,并且所有调用都被编组到该线程。类工厂只会在该线程上调用。
  • Apartment. 这表明该类可以在任何单线程模式线程上运行。如果创建它的线程是 STA 线程,则该对象将在该线程上运行,否则将在主 STA 中创建——如果不存在主 STA,则会为其创建一个 STA 线程。(这意味着创建 Apartment 对象的 MTA 线程会将所有调用编组到不同的线程。)类工厂可以由多个 STA 线程并发调用,因此它必须保护其内部数据不受此影响。
  • Free. 这表示设计为在 MTA 中运行的类。它将始终加载到 MTA 中,即使是由 STA 线程创建的,这也意味着 STA 线程的调用将被编组。这是因为Free通常写入对象时期望它可以阻塞。
  • Both. 这些类是灵活的,可以加载到创建它们的任何公寓中。然而,它们的编写必须满足这两组要求:它们必须保护它们的内部状态免受并发调用的影响,以防它们被加载到 MTA 中,但不能阻塞,以防它们被加载到 STA 中。

From the .NET Framework, basically just use [STAThread]on any thread that creates UI. Worker threads should use the MTA, unless they're going to use Apartment-marked COM components, in which case use the STA to avoid marshalling overhead and scalability problems if the same component is called from multiple threads (as each thread will have to wait for the component in turn). It's much easier all around if you use a separate COM object per thread, whether the component is in the STA or MTA.

从 .NET Framework 开始,基本上只[STAThread]在创建 UI 的任何线程上使用。工作线程应该使用 MTA,除非他们要使用带Apartment标记的 COM 组件,在这种情况下,如果从多个线程调用同一个组件,则使用 STA 来避免编组开销和可伸缩性问题(因为每个线程都必须等待组件依次)。如果您为每个线程使用一个单独的 COM 对象,那么无论组件是在 STA 中还是在 MTA 中,都会更容易。

回答by Weipeng L

I find the existing explanations too gobbledygook. Here's my explanation in plain English:

我发现现有的解释太古怪了。这是我用简单的英语解释:

STA: If a thread creates a COM object that's set to STA (when calling CoCreateXXX you can pass a flag that sets the COM object to STA mode), then only this thread can access this COM object (that's what STA means - Single Threaded Apartment), other thread trying to call methods on this COM object is under the hood silently turned into delivering messages to the thread that creates(owns) the COM object. This is very much like the fact that only the thread that created a UI control can access it directly. And this mechanism is meant to prevent complicated lock/unlock operations.

STA:如果一个线程创建了一个设置为 STA 的 COM 对象(在调用 CoCreateXXX 时,您可以传递一个将 COM 对象设置为 STA 模式的标志),那么只有这个线程可以访问这个 COM 对象(这就是 STA 的意思 - 单线程单元),尝试调用此 COM 对象上的方法的其他线程在幕后默默地变成向创建(拥有)COM 对象的线程传递消息。这非常类似于只有创建 UI 控件的线程才能直接访问它。这种机制旨在防止复杂的锁定/解锁操作。

MTA: If a thread creates a COM object that's set to MTA, then pretty much every thread can directly call methods on it.

MTA:如果一个线程创建了一个设置为 MTA 的 COM 对象,那么几乎每个线程都可以直接调用它的方法。

That's pretty much the gist of it. Although technically there're some details I didn't mention, such as in the 'STA' paragraph, the creator thread must itself be STA. But this is pretty much all you have to know to understand STA/MTA/NA.

这就是它的要点。尽管从技术上讲,有些细节我没有提及,例如在“STA”段落中,但创建者线程本身必须是 STA。但这几乎是您了解 STA/MTA/NA 所需要知道的全部内容。

回答by Brian ONeil

STA (Single Threaded Apartment) is basically the concept that only one thread will interact with your code at a time. Calls into your apartment are marshaled via windows messages (using a non-visible) window. This allows calls to be queued and wait for operations to complete.

STA(Single Threaded Apartment)基本上是一个概念,即一次只有一个线程会与您的代码进行交互。对您公寓的呼叫通过 Windows 消息(使用不可见的)窗口进行编组。这允许调用排队并等待操作完成。

MTA (Multi Threaded Apartment) is where many threads can all operate at the same time and the onus is on you as the developer to handle the thread security.

MTA(多线程单元)是许多线程可以同时运行的地方,开发人员有责任处理线程安全。

There is a lot more to learn about threading models in COM, but if you are having trouble understanding what they are then I would say that understanding what the STA is and how it works would be the best starting place because most COM objects are STA's.

关于 COM 中的线程模型还有很多需要了解,但是如果您在理解它们是什么方面遇到困难,那么我会说理解 STA 是什么以及它是如何工作的将是最好的起点,因为大多数 COM 对象都是 STA。

Apartment Threads, if a thread lives in the same apartment as the object it is using then it is an apartment thread. I think this is only a COM concept because it is only a way of talking about the objects and threads they interact with…

单元线程,如果一个线程与它正在使用的对象位于同一个单元中,那么它就是单元线程。我认为这只是一个 COM 概念,因为它只是一种谈论它们与之交互的对象和线程的方式……

回答by Nick

Each EXE which hosts COM or OLE controls defines it's apartment state. The apartment state is by default STA (and for most programs should be STA).

每个承载 COM 或 OLE 控件的 EXE 都定义了它的单元状态。公寓状态默认为 STA(对于大多数程序应该是 STA)。

STA- All OLE controls by necessity must live in a STA. STA means that your COM-object must be always manipulated on the UI thread and cannot be passed to other threads (much like any UI element in MFC). However, your program can still have many threads.

STA- 根据需要,所有 OLE 控件都必须位于 STA 中。STA 意味着您的 COM 对象必须始终在 UI 线程上操作并且不能传递给其他线程(很像 MFC 中的任何 UI 元素)。但是,您的程序仍然可以有很多线程。

MTA- You can manipulate the COM object on any thread in your program.

MTA- 您可以在程序中的任何线程上操作 COM 对象。

回答by Kevin C.

As my understanding, the 'Apartment' is used to protect the COM objects from multi-threading issues.

据我了解,“公寓”用于保护 COM 对象免受多线程问题的影响。

If a COM object is not thread-safe, it should declare it as a STA object. Then only the thread who creates it can access it. The creation thread should declare itself as a STA thread. Under the hood, the thread stores the STA information in its TLS(Thread Local Storage). We call this behavior as that the thread enters a STA apartment. When other threads want to access this COM object, it should marshal the access to the creation thread. Basically, the creation thread uses messages mechanism to process the in-bound calls.

如果 COM 对象不是线程安全的,则应将其声明为 STA 对象。那么只有创建它的线程才能访问它。创建线程应将自身声明为 STA 线程。在幕后,线程将 STA 信息存储在其 TLS(线程本地存储)中。我们称这种行为为线程进入 STA 单元。当其他线程想要访问这个 COM 对象时,它应该编组对创建线程的访问。基本上,创建线程使用消息机制来处理入站调用。

If a COM object is thread-safe, it should declare it as a MTA object. The MTA object can be accessed by multi-threads.

如果 COM 对象是线程安全的,则应将其声明为 MTA 对象。MTA 对象可以被多线程访问。

回答by user2696845

Code that calls COM object dlls (for example, to read proprietary data files), may work fine in a user interface but hang mysteriously from a service. The reason is that as of .Net 2.0 user interfaces assume STA (thread-safe) while services assume MTA ((before that, services assumed STA). Having to create an STA thread for every COM call in a service can add significant overhead.

调用 COM 对象 dll(例如,读取专有数据文件)的代码可能在用户界面中运行良好,但在服务中神秘挂起。原因是从 .Net 2.0 开始,用户界面采用 STA(线程安全),而服务采用 MTA(在此之前,服务采用 STA)。必须为服务中的每个 COM 调用创建一个 STA 线程会增加大量开销。