Fragensteller
Threading - Thread vorzeitig beenden

Frage
-
Hi,
ich tue mit ThreadStart einen Process starten. In dem Prozess wartet dann ein NamedPipeServerStream auf einen Connect. Geschieht der wird der nachfolgende Code abgearbeitet und der thread ist beendet. Nun aber kommt es vohr das es kein Connect gibt und das Vaterprocess von dem ThreadProcess beendet wird. Dann ist aber immer noch das ThreadProcess aktiv, weil er an der WaitForConnection(); stellte steht und sich nicht von (Thread)->Abort(); beeindrucken läst.
Wie umgehe ich dieses Problem ohne einen eigenconnect durch führen zu müssen bei beendigung ohne einnen Processfremden connect?
Alle Antworten
-
> ich tue mit ThreadStart einen Process starten.
Mit "ThreadStart" kann man keinen Process starten... eher mit
Process::Start...
Oder meinst Du, dass Du in einem Thread einen Process startest...
> In dem Prozess wartet
> dann ein NamedPipeServerStream auf einen Connect. Geschieht der wird der
> nachfolgende Code abgearbeitet und der thread ist beendet.
Hä?
Der Connect musst ja Du machen, oder?
> Nun aber
> kommt es vohr das es kein Connect gibt und das Vaterprocess von dem
> ThreadProcess beendet wird.
Das verstehe ich nicht....
Dann ist aber immer noch das ThreadProcess
> aktiv, weil er an der WaitForConnection(); stellte steht und sich nicht
> von (Thread)->Abort(); beeindrucken läst.
Man sollte *nie* Thread-Abort verwenden.... mach ein vernünftiges Event
(z.B. AutoResetEvent) und setze dies und warte im Thread auf beide
Events. Dazu musst Du BeginWaitForConnection verwenden und im
IAsyncResult das "result.AsyncWaitHandle" zusammen mit Deinem
"EndEventHandle" verwenden...
> Wie umgehe ich dieses Problem ohne einen eigenconnect durch führen zu
> müssen bei beendigung ohne einnen Processfremden connect?
Wie gesagt: Verwende BeginWaitForConnection und erzeuge ein eigenes
"EndEvent", welches Du von extern setzten kannst; dann kannst Du den
Thread "richtig" beenden... auch wenn kein Connect erfolgte...
Jochen Kalmbach (MVP VC++) -
// Server.cpp: Hauptprojektdatei. #include "stdafx.h" #include "mainForm.h" using namespace Server; using namespace System; using namespace System::Diagnostics; using namespace System::IO; using namespace System::IO::Pipes; void NamedPipeServerStream_WaitForConnectionThreadProcess(void); [STAThreadAttribute] int main(array<System::String ^> ^args) { bool processIsActive = false; Process ^current = Process::GetCurrentProcess(); array<Process ^> ^processes = Process::GetProcessesByName(current->ProcessName); for each (Process ^process in processes) { if(process->Id != current->Id) { if (Reflection::Assembly::GetExecutingAssembly()->Location->Replace("/", "\\") == current->MainModule->FileName) { processIsActive = true; } } } Threading::Thread ^NamedPipeServerStream_WaitForConnection; if(processIsActive == false) { NamedPipeServerStream_WaitForConnection = gcnew Threading::Thread(gcnew Threading::ThreadStart(&NamedPipeServerStream_WaitForConnectionThreadProcess)); NamedPipeServerStream_WaitForConnection->Start(); // Aktivieren visueller Effekte von Windows XP, bevor Steuerelemente erstellt werden Application::EnableVisualStyles(); Application::SetCompatibleTextRenderingDefault(false); // Hauptfenster erstellen und ausführen Application::Run(gcnew mainForm()); } else { System::Text::Decoder ^decoder = System::Text::Encoding::UTF8->GetDecoder(); array<Byte> ^bytes = gcnew array<Byte>(10); array<Char> ^chars = gcnew array<Char>(10); NamedPipeClientStream ^pipeStream = gcnew NamedPipeClientStream("messagepipe"); pipeStream->Connect(); pipeStream->ReadMode = PipeTransmissionMode::Message; int numBytes; do { String ^message = ""; do { numBytes = pipeStream->Read(bytes, 0, bytes->Length); int numChars = decoder->GetChars(bytes, 0, numBytes, chars, 0); message += gcnew String(chars, 0, numChars); } while (!pipeStream->IsMessageComplete); decoder->Reset(); //Console::WriteLine(message); Microsoft::VisualBasic::Interaction::MsgBox(message,Microsoft::VisualBasic::MsgBoxStyle::OkOnly,"messagepipe"); } while (numBytes != 0); } NamedPipeServerStream_WaitForConnection->Abort(); return 0; } void NamedPipeServerStream_WaitForConnectionThreadProcess(void) { System::Text::UTF8Encoding ^encoding = gcnew System::Text::UTF8Encoding(); String ^message1 = "Named Pipe Message Example."; String ^message2 = "Another Named Pipe Message Example."; array<Byte> ^bytes; NamedPipeServerStream ^pipeStream = gcnew NamedPipeServerStream("messagepipe",PipeDirection::InOut,1,PipeTransmissionMode::Message,PipeOptions::None); pipeStream->WaitForConnection(); // Let’s send two messages. bytes = encoding->GetBytes(message1); pipeStream->Write(bytes, 0, bytes->Length); bytes = encoding->GetBytes(message2); pipeStream->Write(bytes, 0, bytes->Length); }
-
PS: Das erkennen, ob ein Prozess schon läuft sollte man über ein
Named-Mutex machen...
PPS: Du kannst den Thread auch als Background-Thread markieren, dan wird
er automatisch beendet, wenn sich das Hauptprogramm beendet...
(thread->IsBackground = true;)
Jochen Kalmbach (MVP VC++) -
PS: Das erkennen, ob ein Prozess schon läuft sollte man über ein
Named-Mutex machen...
PPS: Du kannst den Thread auch als Background-Thread markieren, dan wird
er automatisch beendet, wenn sich das Hauptprogramm beendet...
(thread->IsBackground = true;)
Jochen Kalmbach (MVP VC++)
Wenn der Thread dann geschlossen wird, wurde dann NamedPipeServerStream trotzdem sauber beendet? oder sollte Close() schon noch ausgeführt werden? Den unterschied zwischen WaitForConnection() und BeginWaitForConnection(...) habe ist jetzt verstanden. Während der erste dann an der Stellte bis zum Connect stehen bleibt, bleibt die andere da nicht stehen und arbeitet die Befehle weiter ab.
Wenn ich aber ein Event für das eintreten eines Connect machen möchte muss ich doch aber einen Zeiger transportieren, was mit ParamizedThreadStart nur mit GCHandle::Alloc(...) und CreateObjRef(...) geht oder?
Nichts des trotz scheint mir das so viel Code, das es billiger kommt wenn ich einfach einen eigenconnect mache. Also NamedPipeClientStream instanziere und einfach Connect() aufrufe. Allerdings nur wenn ich bei WaitForConnection bleibe, dann müsste ich aber eine globale wchar_t Variabe anlegen um den empfangenen Stream bzw. die Teile davon aus dem Thread in die wchar_t zu konvertieren. Dann wiederum aber brauche ich ein Event für diese Variable wenn diese sich ändert. -
Wenn das Programm beendet wird, dann wird auch der Server "korrekt" beendet.
> Wenn ich aber ein Event für das eintreten eines Connect machen möchte
> muss ich doch aber einen Zeiger transportieren, was mit
> ParamizedThreadStart nur mit GCHandle::Alloc(...) und CreateObjRef(...)
> geht oder?
Neee.... ja nicht.... warum übergibst Du es nicht direkt? An "Object^"
kannst Du alles übergeben, was Du willst...
> Nichts des trotz scheint mir das so viel Code, das es billiger kommt
enconnect mache.
Ich würde "IsBackground = true" setzen...
>Also NamedPipeClientStream
> instanziere und einfach Connect() aufrufe. Allerdings nur wenn ich bei
> WaitForConnection bleibe, dann müsste ich aber eine globale wchar_t
> Variabe anlegen um den empfangenen Stream bzw. die Teile davon aus dem
> Thread in die wchar_t zu konvertieren. Dann wiederum aber brauche ich
> ein Event für diese Variable wenn diese sich ändert.
Das würde eine Race-Condition erzeugen (wie übrigends auch mit der
Prozess-Erkennung.... deswegen ein Named-Mutex!)
Jochen Kalmbach (MVP VC++) -
Okay, vielleicht nicht der richtige Thread aber es ist die herkunft meiner Frage. Wo sagt mir denn NamedPipeServerStream wenn Connectet wurde nachdem BeginWaitForConnection() ausgeführt wurde. Wird da eine entsprechende Information mit dem IAsyncResult mit überliefert? Bis jetzt bin ich nur so weit:
static void Result(IAsyncResult ^ar) { MsgBox(ar->AsyncState->ToString(),0,""); } [Thread] ... NamedPipeServerStream ^pipeStream = gcnew NamedPipeServerStream("messagepipe",PipeDirection::InOut,1,PipeTransmissionMode::Message,PipeOptions::Asynchronous); pipeStream->BeginWaitForConnection(gcnew AsyncCallback(&Result),"NPSS") ...
Nur wo schreibe ich denn nun das rein was ausgeführt werden sol wenn ein Connect erfolgt ist? Gibt den BeginWaitForConnection gleich immer was zurück (ebenfalls einen IAsyncResult) oder erst wenn das Connect erfolgt ist? -
Es heist hier
Parameter callback Typ: System..::.AsyncCallback Die Methode, die aufgerufen wird, wenn ein Client eine Verbindung mit dem NamedPipeServerStream-Objekt herstellt.
Dennoch kann ich eindeutig festellen, dass die Methode, die aufgerufen werden sol, sofort aufgerufen wird, nach dem BeginWaitForConnection ausgeführt wird, obwohl zu dem zeitpunkt überhaupt noch kein Connect statgefunden haben kann.