03. juni 2003 - 08:53Der er
17 kommentarer og 2 løsninger
Kill af kørende Com Object lavet på MFC/Visual Studio 6.0
Jeg har et Com Object som bliver kaldt fra VS SQL Serveren.
Mit problem er at hvis der opstår en fejl kan mit objekt godt hænge og derfor returneres der aldrig noget til SQL. Jeg kan ikke lave en kill process via joblisten i Windows (adgang nægtet).
Eneste måde at terminere objektet på er at genstarte maskinen hvilket er dybt problematisk for mig.
Er der nogen som har en god idé til hvordan jeg kan ændre objektet så det kan slås ihjel eller så det selv terminerer, hvis det hænger?
Objektet er implementeret som en applikation, men bliver kørt som en service (dvs intet applikationsvindue)
Jeg kender ikke ret meget til thread og processstyring i C++. Og jeg vil gerne have en elegant og hurtig løsning på mit problem eller hjælp til at programmere løsningen (samtidigt med at jeg ikke kan udlevere koden). Derfor har jeg sat points lidt højt.
Normalt ligger der vel en eller anden form for loop-struktur i COM-objektet. Denne loop-struktur bør du tilføje en "udvej" i stil med:
// Globale variabler. Thread *thisPID; bool terminatePID; bool resetTIMER; CKillThread* killThread; : : // Opret "kill" tråden. thisPID = handle; // Fra 'WinMain' eller hvad "main" proceduren nu hedder i COM-objectet. resetTIMER = true; killThread = CreateThread ...; : // Start COM hoved-loop while (!terminatePID) { // Vent på et indkommende request // req = getRequest resetTIMER = true;
// Behandling af indkommende request };
Du kan så udvide dit COM-object med en tråd (Thread) som du lader køre "ved siden af" sådan at den kan kill'en hovedtråden, hvis skidtet går dødt - f.eks. noget i stil med:
void CKillThread::Run(void) { int waitCycle = 1800000; /* Vent 1800 sekunder, dvs. 1/2 time */ while (resetTIMER) // Samme switch som i selve COM-tråden - den skal i princippet kodes "thread"-safe, men i denne sammenhæng betyder evt. manglende synkronisering kun at der går een "wait" cycle mere. { resetTIMER = false; Sleep(waitCycle); };
Normalt stopper et COM Object når dets RefCount er 0. Der er desværre ikke nogen måde at terminere et (normalt) COM Object med...
Men, når nu dit er implementeret som en service er det måske en mulighed alligevel... Har du mulighed for at opdage, fra Objectet, at det hænger? Hvis du kan det kan du prøve at stoppe servicen og starte den igen, og hvis du ikke kan det kan du slå den ihjel med TerminateProcess() For at stoppe og starte servicen, fra servicen, kan du lave en batfil med følgende 2 linier
net stop dinservice net start dinservice
og så kalde denne fil fra servicen, evt. med ShellExecute()...
soepro - vil du ikke dræber dit COM object hvis der ikke kommer nogen request til COM hoved loopet, da du ikke får sat resetTIMER hvis der ikke er nogen request?
tam >> Så COM-objectet aktiveres med et specifikt kald, som blot aldrig returnerer eller ? Kan Thread ideen ikke stadig bruges, hvis man kan sætte en maksimal "wait-time" på at COM-servicen skal returnere ?
Jeg er lidt ked af at sige det, men mit objekt kører ikke som en service i NT-sammenhæng. Det jeg mente med det (I må undskylde min knudrede terminologi) var blot at der var ikke noget vindue med menuer på eller noget.
Når applikationen hænger kan det være fordi der er en dialog-boks (jeg har ikke styr over al koden selv pga kodegenbrug). Dialogen kommer ikke frem på skærmen men applikationen venter alligevel på et OK eller CANCEL.
En anden mulighed kan være at dens kald til en database hænger eller en helt tredie og ukendt mulighed ;-)
segmose >> Forskellen på de to (altså hænge <> ikke modtage noget) bliver svær at fange, sådan som jeg ser det. En løsning må så være kun starte 'killer' tråden, såfremt man er i gang med at behandle et request:
comObject::Method(void) { killThread.ResetTimer(); // Hvis dette ikke kan "overloades" ind i trådens 'OnResume' event. (Kan man i C++ Builder's TThread.) killThread.Resume();
Ovenstående bevirker selvfølgelig er der er en maksimal tid COM-objektet må (kan) bruge på at behandle et request - hvis den ikke er færdig inden waitCycle er nået, så slår COM-objektet siig selv ihjel.
segmose >> Udnytte constructoren og de-constructoren samt "out of scope" delete - OK det er smartere !
Din metode betyder vel at hver metode har sin egen "killer" thread - betyder det ikke at det første request der "time-outer" killer alle igangværende requests ? Eller bliver de enkelte requests/metode kald rent faktisk behandlet under hver sin PID ?
"segmose >> Udnytte constructoren og de-constructoren samt "out of scope" delete - OK det er smartere ! " Ja, jeg synes også at Bjarne er meget smart :)
Det kommer jo an på hvordan man ønsker det, hvis der er flere forskellige processer der kalder COM-objectet samtidig (har de så forskellig pid? jeg ved det ikke da jeg ikke har nogen erfaring med COM) skal man nok overveje nøje om man vil skyde alle igangværende (metode 1) hvis en får timeout. Hvilket også var grunden til at jeg tilføjede ResetTimer/Resume/Suspend (metode 2) til (de-)constructor, hvor alt efter brug jeg så skulle vælge den rigtig metode.
Der er jo altid problemer/udfordringer med: - threaded Kan vi skyde på thread niveau eller kun på process niveau? - reentrant Metode 2: hvis man har en fælles timeout kan man få det tilfælde at en process hænger men der hele tiden kommer nye så timeren bliver reset hele tiden og man derfor ikke vil få løst problemet, så skulle jeg udvide kill med en anden timeout der checker om der findes et tidspunkt hvor kun en process kører (den der hænger) før jeg skyder objectet, og ellers skyder alle alligevel efter en tid hvis der aldrig er mindre end 2 processer. - deadlock ud over at selve COM-objectet skal undgå deadlocks, skal CKillThread/KillThread også.
Tak for svarene og undskyld jeg var så lang tid om at give points. Jeg har ikke været på arbejde :-)
I må deles om points fordi så vidt jeg kan se så hjalp I hinanden til at give det endelige råd.
Synes godt om
Ny brugerNybegynder
Din løsning...
Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.