Single-Threaded Lägenheter
Att använda entrådade lägenheter (lägenhetsmodellprocessen) erbjuder ett meddelandebaserat paradigm för att hantera flera objekt som körs samtidigt. Det gör att du kan skriva effektivare kod genom att låta en tråd, medan den väntar på att en viss tidskrävande åtgärd ska slutföras, tillåta att en annan tråd körs.
Varje tråd i en process som initieras som en lägenhetsmodellprocess, och som hämtar och skickar fönstermeddelanden, är en enkeltrådad lägenhetstråd. Varje tråd bor i sin egen lägenhet. I en lägenhet kan gränssnittspekare skickas utan marskalkning, och därför kommunicerar alla objekt i en enda trådad lägenhetstråd direkt.
En logisk gruppering av relaterade objekt som alla körs på samma tråd, och därför måste ha synkron körning, kan finnas i samma entrådade lägenhetstråd. Ett lägenhetsmodellobjekt kan dock inte finnas i mer än en tråd. Anrop till objekt i andra trådar måste göras i kontexten för den ägande tråden, så distribuerade COM växlar trådar åt dig automatiskt när du anropar en proxy.
Modellerna interprocess och interthread liknar varandra. När det är nödvändigt att skicka en gränssnittspekare till ett objekt i en annan lägenhet (på en annan tråd) inom samma process använder du samma marskalkeringsmodell som objekt i olika processer använder för att skicka pekare över processgränser. Genom att hämta en pekare till standardmarheringsobjektet kan du konvertera gränssnittspekare över trådgränser (mellan lägenheter) på samma sätt som du gör mellan processerna. (Gränssnittspekare måste konverteras när de skickas mellan lägenheter.)
Regler för entrådade lägenheter är enkla, men det är viktigt att följa dem noggrant:
- Varje objekt ska bara finnas på en tråd (inom en entrådad lägenhet).
- Initiera COM-biblioteket för varje tråd.
- Konvertera alla pekare till objekt när du skickar dem mellan lägenheter.
- Varje enskild trådad lägenhet måste ha en meddelandeloop för att hantera anrop från andra processer och lägenheter inom samma process. Entrådade lägenheter utan objekt (endast klient) behöver också en meddelandeloop för att skicka de sändningsmeddelanden som vissa program använder.
- DLL-baserade eller processbaserade objekt anropar inte COM-initieringsfunktionerna. I stället registrerar de sin trådningsmodell med ThreadingModel namngivet värde under InprocServer32 nyckel i registret. Lägenhetsmedvetna objekt måste också skriva DLL-startpunkter noggrant. Det finns särskilda överväganden som gäller för trådning av processerver. Mer information finns i In-Process servertrådsproblem.
Även om flera objekt kan leva på en enda tråd, kan inget lägenhetsmodellobjekt leva på mer än en tråd.
Varje tråd i en klientprocess eller en out-of-process-server måste anropa CoInitializeeller anropa CoInitializeEx och ange COINIT_APARTMENTTHREADED för parametern dwCoInit. Huvudlägenheten är tråden som anropar CoInitializeEx först. Information om processerver finns i In-Process servertrådsproblem.
Alla anrop till ett objekt måste göras på dess tråd (i lägenheten). Det är förbjudet att anropa ett objekt direkt från en annan tråd. om du använder objekt på det här fria sättet kan det orsaka problem för program. Konsekvensen av den här regeln är att alla pekare på objekt måste konverteras när de skickas mellan lägenheter. COM tillhandahåller följande två funktioner för detta ändamål:
- CoMarshalInterThreadInterfaceInStream konverterar ett gränssnitt till ett dataströmobjekt som returneras till anroparen.
- CoGetInterfaceAndReleaseStream tar bort en gränssnittspekare från ett strömobjekt och släpper den.
Dessa funktioner omsluter anrop till funktionerna CoMarshalInterface och CoUnmarshalInterface, vilket kräver att flaggan MSHCTX_INPROC används.
I allmänhet utförs marskalkeringen automatiskt av COM. När du till exempel skickar en gränssnittspekare som en parameter i ett metodanrop på en proxy till ett objekt i en annan lägenhet, eller när du anropar CoCreateInstance, utför COM marskalkeringen automatiskt. Men i vissa specialfall, där programskrivaren skickar gränssnittspekare mellan lägenheter utan att använda de normala COM-mekanismerna, måste författaren hantera marskalkningen manuellt.
Om en lägenhet (lägenhet 1) i en process har en gränssnittspekare och en annan lägenhet (lägenhet 2) kräver dess användning, måste lägenhet 1 ringa CoMarshalInterThreadInterfaceInStream för att konvertera gränssnittet. Strömmen som skapas av den här funktionen är trådsäker och måste lagras i en variabel som kan nås av Lägenhet 2. Lägenhet 2 måste skicka den här strömmen till CoGetInterfaceAndReleaseStream för att avmarshala gränssnittet och kommer att få tillbaka en pekare till en proxy genom vilken den kan komma åt gränssnittet. Huvudlägenheten måste vara vid liv tills klienten har slutfört allt COM-arbete (eftersom vissa processobjekt läses in i huvudlägenheten, enligt beskrivningen i In-Process Server Threading Issues). När ett objekt har skickats mellan trådar på det här sättet är det mycket enkelt att skicka gränssnittspekare som parametrar. På så sätt utför distribuerad COM växlingen av marskalkering och tråd för programmet.
För att hantera anrop från andra processer och lägenheter inom samma process måste varje enskild trådad lägenhet ha en meddelandeloop. Det innebär att trådens arbetsfunktion måste ha en GetMessage/DispatchMessage-loop. Om andra synkroniseringsprimärer används för att kommunicera mellan trådar kan funktionen MsgWaitForMultipleObjects användas för att vänta både på meddelanden och för trådsynkroniseringshändelser. Dokumentationen för den här funktionen innehåller ett exempel på den här typen av kombinationsloop.
COM skapar ett dolt fönster med windowsklassen "OleMainThreadWndClass" i varje enskild trådad lägenhet. Ett anrop till ett objekt tas emot som ett fönstermeddelande till det här dolda fönstret. När objektets lägenhet hämtar och skickar meddelandet kommer det dolda fönstret att ta emot det. Fönsterproceduren anropar sedan motsvarande gränssnittsmetod för objektet.
När flera klienter anropar ett objekt placeras anropen i kö i meddelandekön och objektet får ett samtal varje gång lägenheten hämtar och skickar meddelanden. Eftersom anropen synkroniseras av COM och anropen alltid levereras av tråden som tillhör objektets lägenhet, behöver objektets gränssnittsimplementeringar inte tillhandahålla synkronisering. Entrådade lägenheter kan implementera IMessageFilter så att de kan avbryta samtal eller ta emot fönstermeddelanden vid behov.
Objektet kan återaktiveras om någon av dess gränssnittsmetodimplementeringar hämtar och skickar meddelanden eller gör ett ORPC-anrop till en annan tråd, vilket gör att ett annat anrop levereras till objektet (av samma lägenhet). OLE förhindrar inte återaktivering på samma tråd, men det kan hjälpa till att ge trådsäkerhet. Detta är identiskt med det sätt på vilket en fönsterprocedur kan skickas igen om den hämtar och skickar meddelanden när ett meddelande bearbetas. Men om du anropar en okonserver med enkeltrådad lägenhet som anropar en annan enskild trådad lägenhetsserver kan den första servern återaktiveras.
Relaterade ämnen
-
Single-Threaded och för flertrådad kommunikation