Single-Threaded Apartmanok
Az egyszálú apartmanok (a lakásmodell folyamata) üzenetalapú paradigmát kínál az egyidejűleg futó több objektum kezelésére. Ez lehetővé teszi, hogy hatékonyabb kódot írjon egy szál engedélyezésével, miközben egy időigényes művelet befejeződik, és lehetővé teszi egy másik szál végrehajtását.
A lakásmodell-folyamatként inicializált, ablaküzeneteket lekérő és küldő folyamatok minden szála egyszálas lakásszál. Minden szál a saját lakásában él. Egy lakáson belül az interfészmutatók átadhatók marshaling nélkül, ezért az egyszálas lakásszál összes objektuma közvetlenül kommunikál.
A kapcsolódó objektumok logikai csoportosítása, amelyek mindegyike ugyanazon a szálon fut, és ezért szinkron végrehajtással kell rendelkeznie, ugyanazon az egyszálas lakásszálon élhet. Egy lakásmodell objektuma azonban nem lehet több szálon. A többi szál objektumait a tulajdonosi szál környezetében kell meghívni, így az elosztott COM automatikusan átváltja a szálakat, amikor proxyt hív meg.
Az interprocess és az interthread modellek hasonlóak. Ha egy felületmutatót egy másik lakásban (egy másik szálon) lévő objektumnak kell átadnia ugyanazon a folyamaton belül, ugyanazt a marsallási modellt használja, amelyet a különböző folyamatok objektumai a folyamathatárok közötti mutatók továbbítására használnak. Ha a szabványos marsall objektumra mutató mutatót kap, ugyanúgy illesztheti a szálhatárok (lakások közötti) illesztőmutatókat, mint a folyamatok között. (Az illesztőmutatókat az apartmanok közötti áthaladáskor kell megadni.)
Az egyszálas apartmanok szabályai egyszerűek, de fontos, hogy gondosan kövessék őket:
- Minden objektumnak csak egy szálon kell élnie (egyszálas lakásban).
- Inicializálja a COM-kódtárat minden szálhoz.
- Az összes mutatót vigye az objektumokra, amikor azokat az apartmanok között továbbítja.
- Minden egyszálú lakásnak rendelkeznie kell egy üzenethurkkal, amely kezeli az ugyanazon folyamaton belüli más folyamatokból és apartmanokból érkező hívásokat. Az objektumok nélküli egyszálú apartmanoknak (csak ügyfélnek) üzenethurkra is szükségük van az egyes alkalmazások által használt közvetített üzenetek küldéséhez.
- A DLL-alapú vagy a folyamaton belüli objektumok nem nevezik a COM inicializálási függvényeket; ehelyett regisztrálják a szálmodellt a ThreadingModel elnevezett értéken az InprocServer32 kulcs alatt a beállításjegyzékben. A lakásérzékeny objektumoknak a DLL-belépési pontokat is gondosan meg kell írniuk. A folyamaton belüli kiszolgálók szálkezelésére speciális szempontok vonatkoznak. További információ: In-Process kiszolgálói szálkezelés problémái.
Bár több objektum is élhet egyetlen szálon, egyetlen lakásmodell-objektum sem élhet egynél több szálon.
Egy ügyfélfolyamat vagy folyamaton kívüli kiszolgáló minden szálának meg kell hívnia CoInitialize, vagy meghívnia CoInitializeEx, és meg kell adnia COINIT_APARTMENTTHREADED a dwCoInit paraméterhez. A fő apartman az a szál, amely először meghívja CoInitializeEx. A folyamaton belüli kiszolgálókról további információt a In-Process kiszolgálószál-feldolgozási problémákcímű témakörben talál.
Az objektum minden hívását a szálán (a lakásán belül) kell végrehajtani. Tilos egy objektumot közvetlenül egy másik szálból meghívni; az objektumok ilyen szabad szálú használata problémákat okozhat az alkalmazások számára. Ennek a szabálynak az a következménye, hogy az objektumokra mutató összes mutatót a lakások közötti áthaladáskor kell végrehajtani. A COM a következő két függvényt biztosítja erre a célra:
- CoMarshalInterThreadInterfaceInStream a hívónak visszaadott streamobjektumba illeszti a felületet.
- CoGetInterfaceAndReleaseStream feloldja a felületmutatót egy streamobjektumból, és felszabadítja azt.
Ezek a függvények CoMarshalInterface és CoUnmarshalInterface függvényekre irányuló hívásokat csomagolnak, amelyekhez a MSHCTX_INPROC jelző használata szükséges.
Általánosságban elmondható, hogy a com automatikusan végrehajtja a marsallást. Ha például egy felületmutatót paraméterként ad át egy metódusban, meghív egy proxyt egy másik lakásban lévő objektumra, vagy ha CoCreateInstancehív meg, a COM automatikusan elvégzi a marsallást. Bizonyos speciális esetekben azonban, amikor az alkalmazásíró a szokásos COM-mechanizmusok használata nélkül ad át interfészmutatókat a lakások között, az írónak manuálisan kell kezelnie a marsallást.
Ha egy lakás (Apartman 1) egy folyamatban van egy interfész mutató, és egy másik lakás (Apartman 2) megköveteli a használatát, Apartman 1 kell hívnia CoMarshalInterThreadInterfaceInStream, hogy marshal a felület. A függvény által létrehozott stream szálbiztos, és a 2. apartman által elérhető változóban kell tárolni. A 2. apartmannak át kell adnia ezt a streamet CoGetInterfaceAndReleaseStream a felület leválasztásához, és vissza fog kapni egy mutatót egy proxyhoz, amelyen keresztül hozzáférhet a felülethez. A fő apartmannak életben kell maradnia, amíg az ügyfél nem végezte el az összes COM-munkát (mivel néhány folyamatban lévő objektum be van töltve a fő apartmanba, a In-Process kiszolgálói szálkezelés problémáinak). Miután egy objektumot átadtak a szálak között ilyen módon, nagyon egyszerű paraméterként átadni az interfészmutatókat. Ily módon az elosztott COM elvégzi az alkalmazás marsallását és szálváltását.
Ha más folyamatokból és apartmanokból érkező hívásokat szeretne kezelni ugyanazon a folyamaton belül, minden egyszálú lakásnak rendelkeznie kell egy üzenethurokkal. Ez azt jelenti, hogy a szál munkafüggvényének GetMessage/DispatchMessage hurokkal kell rendelkeznie. Ha más szinkronizálási primitíveket használnak a szálak közötti kommunikációhoz, az MsgWaitForMultipleObjects függvény használható az üzenetek és a szálszinkronizálási események várakozására. A függvény dokumentációja egy példa erre a kombinációs ciklusra.
A COM egy rejtett ablakot hoz létre az "OleMainThreadWndClass" Windows-osztály használatával minden egyszálas lakásban. Az objektum hívása ablaküzenetként érkezik erre a rejtett ablakra. Amikor az objektum lakása lekéri és elküldi az üzenetet, a rejtett ablak megkapja. Az ablak eljárás ezután meghívja az objektum megfelelő interfészmetódusát.
Amikor több ügyfél meghív egy objektumot, a hívások várólistára kerülnek az üzenetsorban, és az objektum minden alkalommal hívást kap, amikor a lakása lekéri és kézbesíti az üzeneteket. Mivel a hívásokat COM szinkronizálja, és a hívásokat mindig az objektum lakásához tartozó szál kézbesíti, az objektum felületi implementációinak nem kell szinkronizálást biztosítaniuk. Az egyszálú apartmanok IMessageFilter implementálhatnak, hogy szükség esetén megszakítsák a hívásokat, vagy fogadják az ablaküzeneteket.
Az objektumot újra lehet küldeni, ha az egyik felületi metódus implementációja lekéri és kézbesíti az üzeneteket, vagy ORPC-hívást indít egy másik szálra, így egy másik hívás érkezik az objektumhoz (ugyanazon a lakáson keresztül). Az OLE nem akadályozza meg az ugyanazon a szálon történő újrabehelyeztetéseket, de segíthet a szál biztonságának biztosításában. Ez megegyezik az ablakeljárások újraküldésének módjával, ha üzeneteket kér le és küld el egy üzenet feldolgozása során. Ha azonban egy folyamaton kívüli, egyszálú apartmankiszolgálót hív meg, amely egy másik egyszálas apartmankiszolgálót hív meg, lehetővé teszi az első kiszolgáló újraküldését.
Kapcsolódó témakörök