STAThread и многопоточность

103

Из статьи MSDN о STAThread:

Указывает, что модель потоков COM для приложения является однопоточным подразделением (STA).

(Для справки, это вся статья .)

Однопоточная квартира ... Ладно, это перебило меня. Кроме того, я где-то читал, что если ваше приложение не использует COM-взаимодействие, этот атрибут вообще ничего не делает. Так что именно он делает и как влияет на многопоточные приложения? Должны ли многопоточные приложения (которые включают в себя все, от тех, кто использует Timers до вызовов асинхронных методов, а не только пулы потоков и т.п.) использовать MTAThread, даже если это «на всякий случай»? Что на самом деле делают STAThread и MTAThread?

Мэтью Шарли
источник

Ответы:

61

Распределение потоков по квартирам - это концепция COM; Если вы не используете COM и ни один из вызываемых вами API не использует COM «под прикрытием», то вам не нужно беспокоиться о квартирах.

Если вам все же нужно знать квартиры, то детали могут немного усложниться ; Вероятно, упрощенная версия состоит в том, что COM-объекты, помеченные как STA, должны запускаться в STAThread, а COM-объекты, отмеченные MTA, должны выполняться в потоке MTA. Используя эти правила, COM может оптимизировать вызовы между этими различными объектами, избегая маршалинга там, где в этом нет необходимости.

Брюс
источник
7
Это слишком упрощенно. Многопоточные объекты могут выполняться в любом потоке. Объекты с резьбой по квартире могут работать только в той квартире, в которой они были созданы.
1800 ИНФОРМАЦИЯ
28
Вызов от объекта STA в потоке STA к объекту MTA будет маршалирован в поток MTA (если объект MTA не реализует маршалер со свободным потоком). Как я уже сказал, детали могут быть сложными. (Я проработал в команде COM несколько лет, улыбаясь )
Брюс
9
Иногда вам нужно знать об этом, даже если вы не используете COM напрямую. Поток должен использовать модель однопоточного апартамента, если он отображает какие-либо графические окна. Вот почему [STAThread] всегда отображается поверх основного метода в приложении Windows Forms.
Джастин Этье,
6
Разве что-то вроде диалогового окна «Шрифт или файл» не может использовать COM без вашего ведома? Я бы предположил, что они работают внутри, разве это не означает, что почти любое приложение Windows Forms требует установки STAThread? Простите мое наивное предположение, ведь я еще не занимался программированием на COM.
Бретт Райан
4
Более подробный ответ для интересующихся: stackoverflow.com/questions/4154429/apartmentstate-for-dummies
jgauffin
3

Что это значит, это гарантирует, что CoInitialize это вызвано указанием COINIT_APARTMENTTHREADED в качестве параметра. Если вы не используете какие-либо компоненты COM или элементы управления ActiveX, это никак не повлияет на вас. Если да, то это критично.

Элементы управления, которые являются многопоточными, фактически являются однопоточными, их вызовы могут обрабатываться только в том отделе, в котором они были созданы.

Еще немного подробностей из MSDN:

Объекты, созданные в однопоточном подразделении (STA), получают вызовы методов только из потока своего подразделения, поэтому вызовы сериализуются и поступают только на границах очереди сообщений (когда вызывается функция Win32 PeekMessage или SendMessage).

Объекты, созданные в потоке COM в многопоточном подразделении (MTA), должны иметь возможность получать вызовы методов из других потоков в любое время. Обычно вы реализуете некоторую форму управления параллелизмом в коде многопоточного объекта, используя примитивы синхронизации Win32, такие как критические секции, семафоры или мьютексы, чтобы помочь защитить данные объекта.

Когда объект, настроенный для работы в нейтральном многопоточном подразделении (NTA), вызывается потоком, который находится в STA или MTA, этот поток передается в NTA. Если этот поток впоследствии вызывает CoInitializeEx, вызов завершается ошибкой и возвращает RPC_E_CHANGED_MODE.

1800 ИНФОРМАЦИЯ
источник
Статья MSDN полезна с точки зрения COM, но можете ли вы сказать мне, когда .NET вызывает CoInitialize()в ответ на STAThreadатрибут / ApartmentState? Примечание: статья в MSDN находится здесь: функция CoInitializeEx .
jrh
Используется ли thread-> SetApartment дляCoInitialize() внутренних целей ? Я проследил атрибут STAThread до конца, но след остыл (я не могу найти источник Thread::SetApartment). Документирован ли где-нибудь класс Thread из thread.h (COM thread.h)? Это MFC, ATL или что-то еще?
jrh
@jrh Я не знаю больше подробностей, кроме этого, извините
ИНФОРМАЦИЯ о 1800
-15

STAThread написан перед основной функцией проекта графического интерфейса C #. Он ничего не делает, но позволяет программе создать единственный поток.

Zeinth
источник