2010-04-23 13 views
7

Ich habe einen verwalteten Thread, der wartet, blockiert, in einem nicht verwalteten Code (insbesondere bei einem Aufruf von NamedPipeServerStream.WaitForConnection(), die schließlich in unmanaged Code ruft, und bietet nicht bieten ein Timeout).Wie kann ein verwalteter Thread, der in nicht verwaltetem Code blockiert ist, beendet werden?

Ich möchte den Thread sauber zu schließen.

Thread.Abort() hat keine Auswirkungen, bis der Code in den verwalteten Bereich zurückkehrt, was nicht möglich ist, bis ein Client eine Verbindung herstellt, auf die wir nicht warten können.

Ich brauche einen Weg "Schock" aus dem nicht verwalteten Code; oder eine Möglichkeit, den Faden zu töten, selbst wenn er sich in unkontrolliertem Land befindet.

+1

Warum benutzen Sie nicht NamedPipeServerStream.BeginWaitForConnection() statt? – SpaceghostAli

+1

Grundsätzlich, weil der Thread "für immer" auf eine Verbindung warten will (außer beim Herunterfahren). Mit Begin/End WaitForConnection müsste ich beginnen, eine Sekunde warten, nach einer Verbindung oder einem Timeout suchen und eine Schleife nach dem Timeout durchführen. –

+1

Ok, ich verstehe es. Nun, eine kleine Änderung an der Antwort von dtb sollte Ihnen geben, was Sie brauchen. Warten Sie nicht auf asyncResult, sondern warten Sie auf ein freigegebenes WaitHandle, das Sie über den Code festgelegt haben, der den Thread abbrechen soll. – SpaceghostAli

Antwort

19

Haben Sie versucht, die nicht blockierende Methode NamedPipeServerStream.BeginWaitForConnection zu verwenden?

using (NamedPipeServerStream stream = ...) 
{ 
    var asyncResult = stream.BeginWaitForConnection(null, null); 

    if (asyncResult.AsyncWaitHandle.WaitOne(5000)) 
    { 
     stream.EndWaitForConnection(asyncResult); 
     // success 
    } 
} 

Sie müssen nicht unbedingt eine feste Zeitüberschreitung verwenden. Sie können ein ManualResetEvent zu signalisieren verwenden, wenn der Thread für die Verbindung warten sollte aufhören:

ManualResetEvent signal = new ManualResetEvent(false); 

using (NamedPipeServerStream stream = ...) 
{ 
    var asyncResult = stream.BeginWaitForConnection(_ => signal.Set(), null); 

    signal.WaitOne(); 
    if (asyncResult.IsCompleted) 
    { 
     stream.EndWaitForConnection(asyncResult); 
     // success 
    } 
} 

// in other thread 
void cancel_Click(object sender, EventArgs e) 
{ 
    signal.Set(); 
} 
+0

Das Signal muss auch innerhalb eines Callbacks gesetzt werden, das an BeginWaitForConnection übergeben wird. Dann wird das Beispiel abgeschlossen sein. –

1

Es gibt keine Art und Weise ist es, „ordentlich“ shut einen Faden von außen nach unten, wenn das Gewinde unmannaged Code ausgeführt wird. Es gibt ein paar Möglichkeiten, den Thread abrupt zu beenden, aber das ist wahrscheinlich nicht das, was du willst.

Sie sollten stattdessen BeginWaitForConnection verwenden.

0

Eigentlich war die Lösung, die ich verwendet habe (was mir aufgefallen ist, als ich die Frage aufschrieb), nach dem Abbrechen aller Threads, nur um einen Client für jeden Thread zu erstellen (und sofort zu entsorgen).

threads.ForEach(thread=> thread.Abort()); 
    threads.ForEach(thread=> 
       { 
        var client = new PipeClient(ServiceName); 
        client.Connect(); 
        client.Dispose(); 
       }); 

Mit der Verbindung, es gibt Code verwaltet, und der Abort() Tritte in (der Faden fängt Threadabort und reinigt sich selbst nach oben)

Dies funktioniert nicht für den allgemeinen Fall (dh die Frage in den Titel gestellt), aber es funktioniert für mich ...

+0

Wenn Sie mit diesem verrückten Schema gehen, achten Sie darauf, eine angemessene Zeitüberschreitung bei Connect zu verwenden, nur für den Fall, dass ein anderer Prozess eine Verbindung im falschen Moment herstellt, wodurch der hörende Thread abbricht und dieser Thread blockiert! –

Verwandte Themen