Udostępnij przez


Problemy z wątkowaniem serwera In-Process

Serwer przetwarzania nie wywołuje CoInitialize, CoInitializeExlub OleInitialize, aby oznaczyć model wątków. W przypadku obiektów opartych na bibliotekach DLL lub działających w procesie, które obsługują wątki, należy ustawić model wątkowania w rejestrze. Domyślnym modelem, gdy nie określisz modelu wielowątkowości, jest pojedynczy wątek na proces. Aby określić model, należy dodać wartość ThreadingModel do klucza InprocServer32 w rejestrze.

Biblioteki DLL, które obsługują tworzenie instancji obiektu klasy, muszą implementować i eksportować funkcje DllGetClassObject oraz DllCanUnloadNow. Gdy klient chce wystąpienia klasy obsługiwanej przez bibliotekę DLL, wywołanie CoGetClassObject (bezpośrednio lub za pomocą wywołania metody CoCreateInstance) powoduje wywołanie DllGetClassObject, aby uzyskać wskaźnik do jego obiektu klasowego, gdy obiekt jest implementowany w DLL. DllGetClassObject powinno zatem mieć możliwość rozdania wielu obiektów klasy lub pojedynczego obiektu bezpiecznego wątkowo (zasadniczo przy użyciu tylko InterlockedIncrement/InterlockedDecrement na ich wewnętrznych licznikach odwołań).

Jak sama nazwa wskazuje, wywołuje się DllCanUnloadNow, aby sprawdzić, czy biblioteka DLL, która ją implementuje, jest używana, co umożliwia bezpieczne zwolnienie biblioteki, jeśli nie jest. Wywołania CoFreeUnusedLibraries z dowolnego wątku zawsze przechodzą przez wątek głównego apartamentu, aby wywołać DllCanUnloadNow.

Podobnie jak inne serwery, serwery w procesie mogą być jednowątkowy, dwuwątkowy lub bezwątkowy. Te serwery mogą być używane przez dowolnego klienta OLE, niezależnie od modelu wątkowania używanego przez tego klienta.

Wszystkie kombinacje współdziałania modelu wątkowego są dozwolone między klientami a obiektami wewnątrz procesu. Interakcja między klientem a obiektem wewnątrzprocesowym, które używają różnych modeli wątków, jest dokładnie taka jak interakcja między klientami a serwerami zewnętrznymi. W przypadku serwera wewnątrzprocesowego, gdy model wątkowy klienta i serwera wewnątrzprocesowego różni się, COM musi umieścić się między klientem a obiektem.

Gdy obiekt w procesie obsługujący model jednowątkowy jest wywoływany jednocześnie przez wiele wątków klienta, com nie może zezwolić wątkom klienta na bezpośredni dostęp do interfejsu obiektu "obiekt nie został zaprojektowany dla takiego dostępu. Zamiast tego com musi upewnić się, że wywołania są synchronizowane i są wykonywane tylko przez wątek klienta, który utworzył obiekt. W związku z tym com tworzy obiekt w głównym mieszkaniu klienta i wymaga, aby wszystkie pozostałe apartamenty klienckie uzyskiwały dostęp do obiektu przy użyciu serwerów proxy.

Gdy w kliencie jest tworzony wielowątkowy model apartamentu, który tworzy serwer przetwarzania wątkowego w procesie, COM uruchamia model jednolity wątków apartamentowych jako wątek "hosta" w kliencie. Ten wątek hosta utworzy obiekt, a wskaźnik interfejsu zostanie przekierowany z powrotem do wielowątkowego apartamentu klienta. Podobnie, gdy apartament jednowątkowy w kliencie modelu apartamentowego tworzy wielowątkowy serwer wewnętrzny, COM uruchamia wielowątkowy wątek hosta (wielowątkowy apartament, na którym zostanie utworzony obiekt, a następnie zostanie przetworzony z powrotem do jednowątkowego apartamentu klienta).

Notatka

Ogólnie rzecz biorąc, jeśli projektujesz niestandardowy interfejs na serwerze wewnątrzprocesowym, powinieneś również dostarczyć dla niego kod marszalingu, aby COM mógł wykonywać marszaling interfejsu między apartamentami klienckimi.

 

COM pomaga chronić dostęp do obiektów udostępnianych przez jednowątkową bibliotekę DLL, wymagając dostępu z tego samego apartamentu klienta, w którym zostały utworzone. Ponadto wszystkie punkty wejścia biblioteki DLL (takie jak DllGetClassObject i DllCanUnloadNow) oraz globalne dane powinny być zawsze dostępne w tym samym apartamencie. COM tworzy takie obiekty w głównym apartamencie klienta, dając głównemu apartamentowi bezpośredni dostęp do wskaźników obiektu. Połączenia z innych kontekstów korzystają z marshalingu międzywątkowego, aby przejść z proxy do stub w głównym wątku, a następnie do obiektu. Dzięki temu com może synchronizować wywołania z obiektem. Wywołania międzywątowe są powolne, dlatego zaleca się ponowne napisanie tych serwerów w celu obsługi wielu mieszkań.

Podobnie jak w przypadku serwera przetwarzania jednowątkowego, obiekt udostępniany przez bibliotekę DLL modelu apartamentu musi być uzyskiwany przez ten sam apartament klienta, z którego został utworzony. Jednak obiekty udostępniane przez ten serwer mogą być tworzone w wielu kontekstach klienta, więc serwer musi wdrożyć punkty wejścia (takie jak DllGetClassObject i DllCanUnloadNow) dla wielowątkowego użycia. Na przykład, jeśli dwa konteksty klienta próbują jednocześnie utworzyć dwa wystąpienia obiektu w ramach procesu, metoda DllGetClassObject może zostać wywołana przez oba konteksty jednocześnie. dllCanUnloadNow należy napisać tak, aby biblioteka DLL nie zwalniała się, podczas gdy kod jest nadal wykonywany w dll.

Jeśli biblioteka DLL udostępnia tylko jedno wystąpienie fabryki klas do tworzenia wszystkich obiektów, implementacja fabryki klas musi być zaprojektowana także do użytku w środowisku wielowątkowym, gdyż będzie używana przez wiele apartamentów klienckich. Jeśli biblioteka DLL tworzy nowe wystąpienie fabryki klas przy każdym wywołaniu DllGetClassObject, fabryka klas nie musi być wątkowo bezpieczna.

Obiekty utworzone przez fabrykę klas nie muszą być bezpieczne wątkowo. Po utworzeniu przez wątek, obiekt jest zawsze dostępny za pośrednictwem tego wątku, a wszystkie wywołania obiektu są synchronizowane przez COM. Model mieszkania klienta, który tworzy ten obiekt, otrzyma bezpośredni wskaźnik do obiektu. Apartamenty klienckie różniące się od apartamentu, w którym utworzono obiekt, muszą uzyskiwać dostęp do obiektu za pośrednictwem serwerów proxy. Te serwery proxy są tworzone, gdy klient marshaluje interfejs między jego apartamentami.

Gdy dla biblioteki DLL ThreadingModel wartość jest ustawiona na "obie", obiekt dostarczony przez tę bibliotekę DLL można utworzyć i użyć bezpośrednio (bez proxy) w apartamentach wątkowych klienta jednowątkowego lub wielowątkowego. Można go jednak używać bezpośrednio tylko w mieszkaniu, w którym został utworzony. Aby nadać obiekt innego apartamentowi, obiekt musi być marshalowany. Obiekt DLL musi zaimplementować własną synchronizację i można uzyskać do niego dostęp z wielu apartamentów użytkowników jednocześnie.

Aby przyspieszyć działanie w przypadku wolnowątkowego dostępu do obiektów DLL działających w procesie, COM udostępnia funkcję CoCreateFreeThreadedMarshaler. Ta funkcja tworzy obiekt marshalingu wielowątkowy, który można agregować z obiektem serwera działającego w procesie. Gdy apartament klienta w tym samym procesie wymaga dostępu do obiektu w innym apartamencie, agregowanie marshalera bezwątkowego zapewnia klientowi bezpośredni wskaźnik do obiektu serwera, zamiast do proxy, gdy klient marshaluje interfejs obiektu do innego apartamentu. Klient nie musi wykonywać żadnej synchronizacji. Działa to tylko w ramach tego samego procesu; Standardowe przeprowadzanie marshalingu służy do odwołowania do obiektu, który jest wysyłany do innego procesu.

Obiekt dostarczany przez bibliotekę DLL w procesie, która obsługuje tylko wolne wątkowanie, jest obiektem z wolnym wątkowaniem. Implementuje własną synchronizację i można uzyskać do niego dostęp przez wiele wątków klienta jednocześnie. Ten serwer nie przekazuje interfejsów między wątkami, więc można go utworzyć i używać bezpośrednio (bez użycia serwera proxy) tylko przez wielowątkowe modele w kliencie. Mieszkania jednowątkowe, które go tworzą, będą uzyskiwać do niego dostęp za pośrednictwem serwera proxy.

uzyskiwanie dostępu do interfejsów w apartamentach

Wybór Modelu Wątkowego

apartamenty wielowątkowe

Procesy, wątki i aplikacje

Single-Threaded i komunikacja wielowątkowa

Single-Threaded Apartamenty