Out-of-Process Server Implementation Helpers
Fyra hjälpfunktioner som kan anropas av out-of-process-servrar är tillgängliga för att förenkla jobbet med att skriva serverkod. COM-klienter och COM-processerver anropar normalt inte dem. Dessa funktioner är utformade för att förhindra konkurrensförhållanden vid serveraktivering när servrarna har flera lägenheter eller flera klassobjekt. De kan dock också lika enkelt användas för enkeltrådade objektservrar och objektservrar med en enda klass. Funktionerna är följande:
För att stänga av korrekt måste en COM-server hålla reda på hur många objektinstanser den har instansierat och hur många gånger dess IClassFactory::LockServer-metoden har anropats. Endast när båda dessa antal når noll kan en server stängas av. I entrådade COM-servrar koordinerades beslutet att stänga av med inkommande aktiveringsbegäranden, som serialiserades av meddelandekön. När servern får en version av den slutliga objektinstansen och beslutar sig för att stänga av, återkallas dess klassobjekt innan fler aktiveringsbegäranden skickas. Om en aktiveringsbegäran kom in efter den här punkten skulle COM känna igen att klassobjekten har återkallats och returnerar ett fel till Service Control Manager (SCM), vilket sedan skulle orsaka att en ny instans av den lokala serverprocessen körs.
Men i en lägenhetsmodellserver, där olika klassobjekt är registrerade på olika lägenheter, och på alla fritrådade servrar, måste det här beslutet att stänga av samordnas med aktiveringsbegäranden över flera trådar så att en tråd på servern inte bestämmer sig för att stänga av medan en annan tråd på servern är upptagen med att dela ut klassobjekt eller objektinstanser. En klassisk men besvärlig metod för att lösa detta är att låta servern, efter att den har återkallat sina klassobjekt, kontrollera antalet instanser igen och hålla sig vid liv tills alla instanser har släppts.
För att göra det enklare för serverskrivare att hantera dessa typer av konkurrensvillkor tillhandahåller COM två referensräkningsfunktioner:
- CoAddRefServerProcess ökar antalet globala referenser per process.
- CoReleaseServerProcess minskar det globala antalet per processreferenser.
När det globala antalet per processreferenser når noll anropar COM automatiskt CoSuspendClassObjects, vilket förhindrar att nya aktiveringsbegäranden kommer in. Servern kan sedan avregistrera sina olika klassobjekt från sina olika trådar på fritiden utan att oroa sig för att en annan aktiveringsbegäran kan komma in. Alla nya aktiveringsbegäranden hanteras hädanefter av SCM som startar en ny instans av den lokala serverprocessen.
Det enklaste sättet för ett lokalt serverprogram att använda dessa funktioner är att anropa CoAddRefServerProcess i konstruktorn för vart och ett av dess instansobjekt och i var och en av dess IClassFactory::LockServer metoder när parametern fLock är TRUE. Serverprogrammet bör också anropa CoReleaseServerProcess i destruktor för vart och ett av dess instansobjekt och i var och en av dess IClassFactory::LockServer metoder när parametern fLockFALSE.
Slutligen bör serverprogrammet vara uppmärksamt på returkoden från CoReleaseServerProcess, och om det returnerar 0 bör serverprogrammet initiera rensningen, vilket för en server med flera trådar vanligtvis innebär att det ska signalera sina olika trådar för att avsluta sina meddelandeslingor och anropa CoAddRefServerProcess och CoReleaseServerProcess. Om livslängdshanteringsfunktionerna för serverprocessen används måste de användas både i objektinstanserna och i metoden LockServer. Annars kan serverprogrammet stängas av i förtid.
När en CoGetClassObject- begäran görs kontaktar COM servern, IClassFactory--gränssnittet för klassobjektet, återgår till klientprocessen, tar bort IClassFactory--gränssnittet och returnerar detta till klienten. I det här läget anropar klienter vanligtvis LockServer- med TRUE- för att förhindra att serverprocessen stängs av. Det finns dock ett tidsfönster mellan när klassobjektet konverteras och när klienten anropar LockServer där en annan klient kan ansluta till samma server, hämta en instans och släppa den instansen, vilket gör att servern stängs av och lämnar den första klienten hög och torr med en frånkopplad IClassFactory- pekare. För att förhindra det här konkurrensvillkoret lägger COM till ett implicit anrop till LockServer med TRUE- till klassobjektet när det konverterar gränssnittet IClassFactory och ett implicit anrop till LockServer med FALSE- när klienten släpper IClassFactory-gränssnittet. Därför är det inte nödvändigt att fjärransluta LockServer anrop tillbaka till servern, och proxyn för LockServer returnerar helt enkelt S_OK utan att faktiskt anropa igen.
Det finns ett annat aktiveringsrelaterat konkurrenstillstånd under initieringen av en out-of-process-serverprocess. En COM-server som registrerar flera klasser anropar vanligtvis CoRegisterClassObject med REGCLS_LOCAL_SERVER för varje CLSID som stöds. När den har gjort detta för alla klasser anger servern sin meddelandeloop. För en entrådad COM-server blockeras alla aktiveringsbegäranden tills servern anger meddelandeloopen. Men för en lägenhetsmodellserver som registrerar olika klassobjekt i olika lägenheter och för alla fritrådade servrar kan aktiveringsbegäranden komma tidigare än så. När det gäller servrar för lägenhetsmodeller kan aktiveringsbegäranden tas emot så snart en tråd har angett sin meddelandeloop. När det gäller fritrådade servrar kan en aktiveringsbegäran komma så snart förstaklassobjektet har registrerats. Eftersom en aktivering kan ske så här tidigt är det också möjligt att den slutliga versionen sker (och därför gör att servern börjar stängas av) innan resten av servern har haft en chans att slutföra initieringen.
För att eliminera dessa konkurrensvillkor och förenkla serverskrivarens jobb bör alla servrar som vill registrera flera klassobjekt med COM anropa CoRegisterClassObject med REGCLS_LOCAL_SERVER | REGCLS_SUSPENDED för varje clsid som servern stöder. När alla klasser har registrerats och serverprocessen är redo att acceptera inkommande aktiveringsbegäranden bör servern göra ett anrop till CoResumeClassObjects. Den här funktionen uppmanar COM att informera SCM om alla registrerade klasser och börjar släppa in aktiveringsbegäranden i serverprocessen. Med de här funktionerna får du följande fördelar:
- Endast ett anrop görs till SCM, oavsett hur många CLSID:er som registreras, vilket minskar den totala registreringstiden (och därmed starttiden för serverprogrammet).
- Om servern har flera lägenheter och olika CLSID:er är registrerade i olika lägenheter, eller om servern är en fritrådad server, kommer inga aktiveringsbegäranden att komma in förrän servern anropar CoResumeClassObjects, vilket ger servern en chans att registrera alla sina CLSID:er och konfigureras korrekt innan de måste hantera aktiveringsbegäranden och eventuella avstängningsbegäranden.
Relaterade ämnen