Из статьи MSDN о STAThread:
Indicates that the COM threading model for an application is single-threaded apartment (STA).
(Для справки, это вся статья.)
Однопоточная квартира ... Ладно, это перешло мне в голову. Кроме того, я где-то читал, что, если ваше приложение не использует COM-взаимодействие, этот атрибут вообще ничего не делает. Итак, что именно он делает и как влияет на многопоточные приложения? Должны ли многопоточные приложения (включая все, от кого-либо, использующего Timer до вызовов асинхронных методов, а не только пулы потоков и т.п.) использовать MTAThread, даже если это «на всякий случай»? Что на самом деле делают STAThread и MTAThread?





Что это делает, это гарантирует, что CoInitialize будет вызван с указанием COINIT_APARTMENTTHREADED в качестве параметра. Если вы не используете какие-либо компоненты COM или элементы управления ActiveX, это никак на вас не повлияет. Если да, то это критически важно.
Элементы управления, которые являются многопоточными, фактически являются однопоточными, их вызовы могут обрабатываться только в том подразделении, в котором они были созданы.
Еще немного подробностей из MSDN:
Objects created in a single-threaded apartment (STA) receive method calls only from their apartment's thread, so calls are serialized and arrive only at message-queue boundaries (when the Win32 function PeekMessage or SendMessage is called).
Objects created on a COM thread in a multithread apartment (MTA) must be able to receive method calls from other threads at any time. You would typically implement some form of concurrency control in a multithreaded object's code using Win32 synchronization primitives such as critical sections, semaphores, or mutexes to help protect the object's data.
When an object that is configured to run in the neutral threaded apartment (NTA) is called by a thread that is in either an STA or the MTA, that thread transfers to the NTA. If this thread subsequently calls CoInitializeEx, the call fails and returns RPC_E_CHANGED_MODE.
Использует ли поток-> SetApartment внутренне CoInitialize()? Я проследил атрибут STAThread до самого конца, но след остыл (я не могу найти источник для Thread::SetApartment). Документирован ли где-нибудь класс Thread из thread.h (COM thread.h)? Это MFC, ATL или что-то еще?
@jrh я не знаю более подробной информации, чем это извините
Распределение потоков по квартирам - это концепция COM; если вы не используете COM и ни один из вызываемых вами API-интерфейсов не использует COM «под прикрытием», то вам не нужно беспокоиться о квартирах.
Если все же нужно знать квартиры, то подробности можно получить немного сложно; Вероятно, упрощенная версия состоит в том, что COM-объекты, помеченные как STA, должны запускаться в STAThread, а COM-объекты, отмеченные MTA, должны выполняться в потоке MTA. Используя эти правила, COM может оптимизировать вызовы между этими различными объектами, избегая маршалинга там, где в этом нет необходимости.
Это слишком упрощенно. Многопоточные объекты могут выполняться в любом потоке. Многопоточные объекты квартиры могут работать только в той квартире, в которой они были созданы.
Вызов объекта STA в потоке STA к объекту MTA будет маршалирован в поток MTA (если объект MTA не реализует маршалер со свободным потоком). Как я уже сказал, детали могут быть сложными. (Я работал в команде COM несколько лет ухмылка)
Иногда вам нужно знать об этом, даже если вы не используете COM напрямую. Поток должен использовать модель однопоточного апартамента, если он отображает какие-либо графические окна. Вот почему [STAThread] всегда отображается поверх основного метода в приложении Windows Forms.
Разве что-то вроде диалогового окна «Шрифт или файл» не может использовать COM без вашего ведома? Я бы предположил, что они работают внутри, разве это не означает, что почти любое приложение Windows Forms потребует установки STAThread? Простите мое наивное предположение, поскольку я на самом деле не занимался программированием COM.
Более подробный ответ для интересующихся: stackoverflow.com/questions/4154429/apartmentstate-for-dummi es
Но вы должны помнить и работать в STA, когда вы программируете пользовательский интерфейс в winforms. Даже если вы не используете COM.
Извините за восстановление старой цепочки комментариев, но @BrettRyan поднимает здесь очень важный вопрос. Я действительно нашел эту ветку, потому что, если вы используете диалог выбора файла в winforms, не отмечая Main () как STAThread, он умрет. Я также могу (слава Богу) подтвердить, что это не повлияло ни на одного из нескольких фоновых воркеров, которые у меня есть в моей программе, предположительно потому, что они, насколько мне известно, не делают никаких вызовов COM.
@BrettRyan - диалог открытия файла не должен быть основан на COM. Однако существует множество активных элементов управления x, которые полагаются на то, что создающий поток находится в STA.
STAThread написан перед основной функцией проекта графического интерфейса C#. Он ничего не делает, но позволяет программе создать единственный поток.
Статья MSDN полезна с точки зрения COM, но можете ли вы сказать мне, когда .NET вызывает
CoInitialize()в ответ на атрибутSTAThread/ApartmentState? Примечание: статья в MSDN находится здесь: Функция CoInitializeEx.