Ответ 1
Информация здесь не конфликтует - она просто не обязательно супер понятна, если вы новичок в COM.
Короткий ответ:
- .Net-потоки всегда для вас всегда соционированы - вам не нужно (и не должно!) называть это самостоятельно.
- ThreadPool нити (и поэтому все, что использует потоки ThreadPool, такие как асинхронные делегаты и т.д.) всегда инициализируется MTA. Единственным вариантом для создания потока STA является либо добавление
[STAThread]
атрибутMain()
, чтобы запросить, чтобы среда выполнения инициализировала основной поток как STA, или используя thread.SetApartmentState(ApartmentState.STA) по новому потоку, который вы создаете перед вызовомthread.Start()
- в противном случае они являются MTA по умолчанию. В любом случае, модель нитечной квартиры не может быть изменена после запуска и запуска потока.
Более длинный ответ: есть два способа вызова CoInitialize - вы можете использовать его для инициализации потока в виде однопоточной резьбы (STA) или в виде многопоточной резьбы (MTA). В приведенном выше тексте говорится, что по умолчанию новые потоки и потоки нити-потока автоматически предварительно конитиализуются как MTA-аромат. Но с новой нитью вы можете использовать ApartmentState для указания STA-аромата, если вы это сделаете, прежде чем начинать поток. Он всегда CoInitialized так или иначе к тому времени, когда он начинался в любом случае.
Обратите внимание, что Main() в программах на основе UI отмечен атрибутом [STAThread], чтобы гарантировать, что он основан на STA; в то время как на консольном приложении отсутствие [STAThread] означает, что CoInited как MTA. Причина этого атрибута, кстати, в том, что поток, который вызывает Main(), является единственным потоком, который вы не можете указать STA vs MTA с помощью ApartmentState, потому что он уже запущен и к моменту выполнения Main(), так слишком поздно использовать это; поэтому подумайте об атрибуте как подсказке для среды выполнения, чтобы установить состояние квартиры до вызова Main().
Ключевым моментом, который следует знать, является то, что STA обычно используется с пользовательским интерфейсом и требует цикла сообщений (который предоставляет вам WinForms.Net); Код STA никогда не должен блокироваться с помощью Sleep() или аналогичного, иначе ваш пользовательский интерфейс также будет блокироваться. С другой стороны, MTA предназначен для использования работниками - например, фоновые задачи, загрузка файлов или выполнение вычислений в фоновом режиме, и, как правило, не должны владеть пользовательским интерфейсом. Вы можете использовать COM из любого из них, но это может зависеть от того, что делает объект COM или откуда вы его взяли. Если это компонент пользовательского интерфейса, вероятно, вы хотите использовать его из потока STA; с другой стороны, если это компонент для загрузки или выполнения вычислений, вы обычно используете его из потока MTA.
Обновление 1 выше в основном говорит о том, что время выполнения .Net всегда вызывает CoInitialize для вас, но позволяет выбрать STA vs MTA, при этом MTA является стандартным.
Обновление 2 выше в основном говорит о том, что поскольку потоки ThreadPool являются MTA (и вы не можете их изменить), вы должны использовать их только для выполнения фоновых операций и не использовать их для задач пользовательского интерфейса.
Обновление 3 говорит, что для новых потоков вы можете выбрать MTA vs STA - то же самое, что и обновление 1, просто более подробно описывая API.
Вся вещь MTA против STA может стать довольно сложной, предложите прочитать эту статью в качестве отправной точки. Большая картина, однако, в основном сводится к тому, что STA = одиночный поток и пользовательский интерфейс; MTA = несколько потоков, фоновые/рабочие задачи. (STA vs MTA также применяется к объектам, а не только к потокам, а COM выполняет целую кучу работы за кулисами, чтобы различные типы потоков использовали разные типы объектов. Когда это работает хорошо, вы этого не понимаете и может блаженно игнорировать его, но когда вы нажимаете ограничение или ограничение, часто бывает сложно определить, что происходит.)