STAThread i wielowątkowość


103

Z artykułu MSDN na STAThread:

Wskazuje, że model wątków COM dla aplikacji to apartament jednowątkowy (STA).

(Dla porównania to cały artykuł ).

Mieszkanie jednowątkowe ... OK, to przeszło mi przez głowę. Czytałem też gdzieś, że jeśli twoja aplikacja nie używa współdziałania COM, ten atrybut właściwie nic nie robi. Więc co dokładnie robi i jak wpływa na aplikacje wielowątkowe? Czy aplikacje wielowątkowe (które obejmują wszystko, od każdego używającego Timers do wywołań metod asynchronicznych, a nie tylko pule wątków i tym podobne) powinny używać MTAThread, nawet jeśli jest to „tylko dla bezpieczeństwa”? Co właściwie robią STAThread i MTAThread?

Odpowiedzi:


61

Gwintowanie mieszkań jest koncepcją COM; jeśli nie używasz COM i żaden z wywoływanych przez ciebie API nie używa COM "pod osłonami", nie musisz martwić się o mieszkania.

Jeśli musisz wiedzieć o mieszkaniach, szczegóły mogą się nieco skomplikować ; prawdopodobnie nadmiernie uproszczona wersja polega na tym, że obiekty COM oznaczone jako STA muszą być uruchamiane na STAThread, a obiekty COM oznaczone jako MTA muszą być uruchamiane w wątku MTA. Korzystając z tych reguł, COM może optymalizować wywołania między tymi różnymi obiektami, unikając organizowania, gdy nie jest to konieczne.


7
To jest nadmiernie uproszczone. Obiekty wielowątkowe mogą działać w dowolnym wątku. Obiekty gwintowane w mieszkaniu mogą działać tylko w mieszkaniu, w którym zostały utworzone.
1800 INFORMACJA

28
Wywołanie z obiektu STA w wątku STA do obiektu MTA zostanie skierowane do wątku MTA (chyba że obiekt MTA implementuje organizatora swobodnego wątku). Jak powiedziałem, szczegóły mogą się skomplikować. (Pracowałem w zespole COM dla wielu latach uśmiech )
Bruce

9
Czasami musisz być tego świadomy, nawet jeśli nie używasz bezpośrednio modelu COM. Wątek musi używać modelu Mieszkanie jednowątkowe, jeśli wyświetla jakiekolwiek okna graficzne. Z tego powodu [STAThread] jest zawsze wyświetlane na górze głównej metody w aplikacji formularzy systemu Windows.
Justin Ethier

6
Czy coś takiego jak okno dialogowe Czcionka lub Plik nie mogłoby używać COM bez Twojej wiedzy? Zakładam, że robią to wewnętrznie, czy nie oznaczałoby to, że prawie każda aplikacja Windows Forms wymagałaby ustawienia STAThread? Wybacz moje naiwne założenie, ponieważ tak naprawdę nie programowałem COM.
Brett Ryan

4
Bardziej szczegółowa odpowiedź dla zainteresowanych: stackoverflow.com/questions/4154429/apartmentstate-for-dummies
jgauffin

3

Co to robi, to zapewnia CoInitialize nazywane jest określeniem COINIT_APARTMENTTHREADED jako parametru. Jeśli nie używasz żadnych składników COM ani formantów ActiveX, nie będzie to miało żadnego wpływu na Ciebie. Jeśli to zrobisz, będzie to kluczowe.

Formanty wielowątkowe są w rzeczywistości jednowątkowe, wywołania do nich mogą być przetwarzane tylko w mieszkaniu, w którym zostały utworzone.

Więcej szczegółów z MSDN:

Obiekty utworzone w mieszkaniu jednowątkowym (STA) odbierają wywołania metod tylko z wątku swojego mieszkania, więc wywołania są serializowane i docierają tylko do granic kolejki komunikatów (gdy wywoływana jest funkcja Win32 PeekMessage lub SendMessage).

Obiekty utworzone w wątku COM w mieszkaniu wielowątkowym (MTA) muszą mieć możliwość odbierania wywołań metod z innych wątków w dowolnym momencie. Zwykle można zaimplementować pewną formę kontroli współbieżności w kodzie obiektu wielowątkowego przy użyciu prymitywów synchronizacji Win32, takich jak sekcje krytyczne, semafory lub muteksy, aby pomóc chronić dane obiektu.

Gdy obiekt skonfigurowany do działania w mieszkaniu z wątkami neutralnymi (NTA) jest wywoływany przez wątek znajdujący się w STA lub MTA, ten wątek jest przenoszony do NTA. Jeśli ten wątek następnie wywoła CoInitializeEx, wywołanie kończy się niepowodzeniem i zwraca RPC_E_CHANGED_MODE.


Artykuł MSDN jest pomocny z punktu widzenia modelu COM, ale czy możesz mi powiedzieć, kiedy .NET wywołuje CoInitialize()w odpowiedzi na STAThreadatrybut / ApartmentState? Uwaga: artykuł na MSDN jest tutaj: Funkcja CoInitializeEx .
jrh

Czy Thread-> SetApartment jest używany CoInitialize()wewnętrznie? Namierzyłem atrybut STAThread na dole, ale ślad ostygł (nie mogę znaleźć źródła Thread::SetApartment). Czy klasa Thread z thread.h (the COM thread.h) jest gdzieś udokumentowana? Czy to MFC, ATL czy coś innego?
jrh

@jrh Nie znam więcej szczegółów poza tym przepraszam
1800 INFORMACJE

-15

STAThread jest zapisywany przed główną funkcją projektu GUI języka C #. Nie robi nic, ale pozwala programowi utworzyć pojedynczy wątek.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.