apartamenty Single-Threaded
Korzystanie z jednowątkowych mieszkań (proces modelu mieszkania) oferuje model oparty na komunikatach do radzenia sobie z wieloma obiektami uruchomionymi jednocześnie. Umożliwia pisanie bardziej wydajnego kodu, umożliwiając wątkowi oczekiwanie na ukończenie pewnej czasochłonnej operacji w celu umożliwienia wykonania innego wątku.
Każdy wątek w procesie, który jest inicjowany jako proces modelu mieszkania, i który pobiera i wysyła komunikaty okien, jest wątkiem apartamentu jednowątkowego. Każdy wątek mieszka we własnym mieszkaniu. W mieszkaniu wskaźniki interfejsu mogą być przekazywane bez marshalingu, a zatem wszystkie obiekty w jednym wątku apartamentowym komunikują się bezpośrednio.
Logiczne grupowanie powiązanych obiektów wykonywanych w tym samym wątku i w związku z tym musi mieć synchroniczne wykonywanie, może istnieć w tym samym wątku apartamentu jednowątkowego. Jednak obiekt modelu mieszkania nie może znajdować się w więcej niż jednym wątku. Wywołania obiektów w innych wątkach muszą być wykonywane w kontekście wątku należącego do użytkownika, więc rozproszone wątki COM przełącza automatycznie podczas wywoływania serwera proxy.
Modele międzyprocesowe i międzywątne są podobne. Jeśli konieczne jest przekazanie wskaźnika interfejsu do obiektu w innym mieszkaniu (w innym wątku) w ramach tego samego procesu, należy użyć tego samego modelu marshalingu, który obiekty w różnych procesach używają do przekazywania wskaźników przez granice procesu. Dzięki uzyskaniu wskaźnika do standardowego obiektu marshalingowego można marshalingu marshalingu wskaźników interfejsu przez granice wątku (między mieszkaniami) w taki sam sposób, jak między procesami. (Wskaźniki interfejsu muszą być marshaling po przekazaniu między apartamentami).
Zasady dotyczące mieszkań jednowątkowych są proste, ale ważne jest, aby je uważnie przestrzegać:
- Każdy obiekt powinien istnieć tylko na jednym wątku (w jednym wątku).
- Zainicjuj bibliotekę COM dla każdego wątku.
- Przemarsz wszystkie wskaźniki do obiektów podczas przekazywania ich między mieszkaniami.
- Każde jednowątkowy apartament musi mieć pętlę komunikatów do obsługi wywołań z innych procesów i mieszkań w ramach tego samego procesu. Pojedyncze wątkowe apartamenty bez obiektów (tylko klient) wymagają również pętli komunikatów do wysyłania komunikatów rozgłaszanych, z których korzystają niektóre aplikacje.
- Obiekty oparte na bibliotekach DLL lub w procesie nie powodują wywoływania funkcji inicjowania MODELU COM; Zamiast tego rejestrują swój model wątków za pomocą ThreadingModel nazwanej wartości w kluczu InprocServer32 w rejestrze. Obiekty obsługujące mieszkanie muszą również uważnie zapisywać punkty wejścia bibliotek DLL. Istnieją specjalne zagadnienia dotyczące wątkowania serwerów przetwarzania. Aby uzyskać więcej informacji, zobacz In-Process Server Threading Issues.
Chociaż wiele obiektów może żyć w jednym wątku, żaden obiekt modelu mieszkania nie może żyć w więcej niż jednym wątku.
Każdy wątek procesu klienta lub serwera przetwarzania poza procesem musi wywołać CoInitializelub wywołać CoInitializeEx i określić COINIT_APARTMENTTHREADED parametru dwCoInit. Głównym mieszkaniem jest wątek, który najpierw wywołuje CoInitializeEx. Aby uzyskać informacje na temat serwerów przetwarzania, zobacz In-Process Server Threading Issues.
Wszystkie wywołania obiektu muszą być wykonywane na jego wątek (w jego mieszkaniu). Zabronione jest wywoływanie obiektu bezpośrednio z innego wątku; używanie obiektów w ten sposób bezwątkowy może powodować problemy z aplikacjami. Implikacją tej reguły jest to, że wszystkie wskaźniki do obiektów muszą być marshaling po przekazaniu między mieszkaniami. Com udostępnia następujące dwie funkcje w tym celu:
- CoMarshalInterThreadInterfaceInStream marshalsuje interfejs do obiektu strumienia, który jest zwracany do obiektu wywołującego.
- CoGetInterfaceAndReleaseStream unmarshalshals wskaźnik interfejsu z obiektu strumienia i zwalnia go.
Te funkcje opakowują wywołania coMarshalInterface i funkcji CoUnmarshalInterface, które wymagają użycia flagi MSHCTX_INPROC.
Ogólnie rzecz biorąc, marshaling jest realizowane automatycznie przez COM. Na przykład podczas przekazywania wskaźnika interfejsu jako parametru w wywołaniu metody na serwerze proxy do obiektu w innym mieszkaniu lub podczas wywoływania CoCreateInstancecom wykonuje automatyczne przeprowadzanie marshalingu. Jednak w niektórych specjalnych przypadkach, w których moduł zapisywania aplikacji przekazuje wskaźniki interfejsu między mieszkaniami bez korzystania z normalnych mechanizmów COM, moduł zapisywania musi obsługiwać marshaling ręcznie.
Jeśli jedno mieszkanie (apartament 1) w procesie ma wskaźnik interfejsu, a inne mieszkanie (Apartament 2) wymaga jego użycia, apartament 1 musi wywołać CoMarshalInterThreadInterfaceInStream do marshalingu interfejsu. Strumień tworzony przez tę funkcję jest bezpieczny wątkowo i musi być przechowywany w zmiennej dostępnej dla apartamentu 2. Apartament 2 musi przekazać ten strumień do CoGetInterfaceAndReleaseStream, aby usunąć interfejs i wrócić wskaźnik do serwera proxy, za pomocą którego może uzyskać dostęp do interfejsu. Główne mieszkanie musi pozostać aktywne, dopóki klient nie ukończy całej pracy COM (ponieważ niektóre obiekty w procesie są ładowane w głównym mieszkaniu, zgodnie z opisem w In-Process Server Threading Issues). Po przekazaniu jednego obiektu między wątkami w ten sposób bardzo łatwo jest przekazać wskaźniki interfejsu jako parametry. W ten sposób rozproszony com wykonuje marshaling i przełączanie wątków dla aplikacji.
Aby obsługiwać wywołania z innych procesów i mieszkań w ramach tego samego procesu, każde jednowątkowy apartament musi mieć pętlę komunikatów. Oznacza to, że funkcja robocza wątku musi mieć pętlę GetMessage/DispatchMessage. Jeśli inne elementy pierwotne synchronizacji są używane do komunikacji między wątkami, funkcja MsgWaitForMultipleObjects może służyć do oczekiwania zarówno dla komunikatów, jak i zdarzeń synchronizacji wątków. Dokumentacja tej funkcji zawiera przykład tej pętli kombinacji.
Com tworzy ukryte okno przy użyciu klasy Systemu Windows "OleMainThreadWndClass" w każdym mieszkaniu jednowątkowym. Wywołanie obiektu jest odbierane jako komunikat okna do tego ukrytego okna. Gdy mieszkanie obiektu pobiera i wysyła komunikat, ukryte okno go otrzyma. Następnie procedura okna wywoła odpowiednią metodę interfejsu obiektu.
Gdy wielu klientów wywołuje obiekt, wywołania są kolejkowane w kolejce komunikatów, a obiekt będzie odbierał wywołanie za każdym razem, gdy jego mieszkanie pobiera i wysyła komunikaty. Ponieważ wywołania są synchronizowane przez model COM, a wywołania są zawsze dostarczane przez wątek należący do mieszkania obiektu, implementacje interfejsu obiektu nie muszą zapewniać synchronizacji. Pojedyncze wątkowe apartamenty mogą implementować IMessageFilter, aby umożliwić im anulowanie połączeń lub odbieranie komunikatów okien w razie potrzeby.
Obiekt można ponownie uruchomić, jeśli jedna z jego implementacji metody interfejsu pobiera i wysyła komunikaty lub wykonuje wywołanie ORPC do innego wątku, powodując w ten sposób dostarczenie innego wywołania do obiektu (przez to samo mieszkanie). Obiekt OLE nie zapobiega ponownemu wętkowi na tym samym wątku, ale może pomóc zapewnić bezpieczeństwo wątków. Jest to identyczne ze sposobem ponownego uzyskania procedury okna w przypadku pobierania i wysyłania komunikatów podczas przetwarzania komunikatu. Jednak wywołanie serwera apartamentów jednowątkowego poza procesem, który wywołuje inny serwer apartamentów jednowątkowy, pozwoli na ponowne uzyskanie pierwszego serwera.
Tematy pokrewne
-
problemy z wątkami serwera In-Process