Was ist ein guter Weg, Themen zur Abschaltung blockiert auf NamedPipeServer # waitForConnection?

StackOverflow https://stackoverflow.com/questions/607872

  •  03-07-2019
  •  | 
  •  

Frage

ich meine Anwendung starten, die eine Anzahl von Threads laicht, von denen jeder eine NamedPipeServer erstellt (.net 3.5 hinzugefügt Typen für Named Pipe IPC verwaltet) und wartet auf Kunden (Blöcke) zu verbinden. Die Code-Funktionen wie vorgesehen.

private void StartNamedPipeServer()
  {
    using (NamedPipeServerStream pipeStream =
                    new NamedPipeServerStream(m_sPipeName, PipeDirection.InOut, m_iMaxInstancesToCreate, PipeTransmissionMode.Message, PipeOptions.None))
    {
      m_pipeServers.Add(pipeStream);
      while (!m_bShutdownRequested)
      {
        pipeStream.WaitForConnection();
        Console.WriteLine("Client connection received by {0}", Thread.CurrentThread.Name);
        ....  

Jetzt muß ich auch eine Shutdown Methode, um diesen Prozess zu bringen, sauber nach unten. Ich habe versucht, den üblichen bool Flag isShutdownRequested Trick. Aber die PipeStream bleibt auf dem waitForConnection () Aufruf blockiert und der Faden nicht stirbt.

public void Stop()
{
   m_bShutdownRequested = true;
   for (int i = 0; i < m_iMaxInstancesToCreate; i++)
   {
     Thread t = m_serverThreads[i];
     NamedPipeServerStream pipeStream = m_pipeServers[i];
     if (pipeStream != null)
     {
       if (pipeStream.IsConnected)
          pipeStream.Disconnect();
       pipeStream.Close();
       pipeStream.Dispose();
     }

     Console.Write("Shutting down {0} ...", t.Name);
     t.Join();
     Console.WriteLine(" done!");
   }
} 

Join nie zurückgibt.

Eine Option, die ich versuche, knapp aber würde möglicherweise Arbeit ist Thread.Abort zu nennen und die Ausnahme auffressen. Aber es fühlt sich nicht richtig .. Irgendwelche Vorschläge

Aktualisieren 2009-12-22
Es tut uns das nicht früher veröffentlichen .. Das ist, was ich als eine Antwort von Kim Hamilton (BCL-Team) erhalten

  

Der „richtigen“ Weg, um eine unterbrechbare zu tun   WaitForConnection ist zu nennen   BeginWaitForConnection, handhaben die neue   Verbindung in dem Rückruf, und in der Nähe   der Rohrstrom zu stoppen warten für   Verbindungen. Wenn das Rohr geschlossen ist,   EndWaitForConnection wird werfen   ObjectDisposedException die der   Callback-Thread kann fangen, aufzuräumen   alle losen Enden und Ausfahrt sauber.

     

Wir erkennen dies ein weit verbreitetes sein muss   Frage, so jemand in meinem Team ist   Planung über diese bald bloggen.

War es hilfreich?

Lösung

Wechseln Sie auf die asynchrone Version:. BeginWaitForConnection

Wenn es überhaupt abgeschlossen wird, werden Sie eine Flagge brauchen so der Handler Abschluss kann nur EndWaitForConnection alle Ausnahmen zu absorbieren rufen und Beenden (Call End ..., um sicherzustellen, alle Ressourcen der Lage sind, bereinigt werden).

Andere Tipps

Das ist kitschig, aber es ist die einzige Methode, die ich bekommen haben zu arbeiten. Erstellen Sie ein ‚fake‘ Client und eine Verbindung zu Ihrem Named Pipe vorbei waitForConnection zu bewegen. Funktioniert jedes Mal.

Auch selbst Thread.Abort () nicht für mich beheben dieses Problem.


_pipeserver.Dispose();
_pipeserver = null;

using (NamedPipeClientStream npcs = new NamedPipeClientStream("pipename")) 
{
    npcs.Connect(100);
}

Sie können folgende Erweiterungsmethode verwenden. Beachten Sie die Aufnahme von ‚Manual cancelEvent‘ - dieses Ereignis von einem anderen Thread eingestellt werden, um zu signalisieren, dass die Warte connect-Methode jetzt abbrechen sollte und das Rohr schließen. Fügen Sie cancelEvent.Set (), wenn m_bShutdownRequested Einstellung und das Herunterfahren sollte relativ anmutig sein.

    public static void WaitForConnectionEx(this NamedPipeServerStream stream, ManualResetEvent cancelEvent)
    {
        Exception e = null;
        AutoResetEvent connectEvent = new AutoResetEvent(false);
        stream.BeginWaitForConnection(ar =>
        {
            try
            {
                stream.EndWaitForConnection(ar);
            }
            catch (Exception er)
            {
                e = er;
            }
            connectEvent.Set();
        }, null);
        if (WaitHandle.WaitAny(new WaitHandle[] { connectEvent, cancelEvent }) == 1)
            stream.Close();
        if (e != null)
            throw e; // rethrow exception
    }

Ich schrieb diese Erweiterung Methode, um dieses Problem zu lösen:

public static void WaitForConnectionEx(this NamedPipeServerStream stream)
{
    var evt = new AutoResetEvent(false);
    Exception e = null;
    stream.BeginWaitForConnection(ar => 
    {
        try
        {
            stream.EndWaitForConnection(ar);
        }
        catch (Exception er)
        {
            e = er;
        }
        evt.Set();
    }, null);
    evt.WaitOne();
    if (e != null)
        throw e; // rethrow exception
}

Eine Möglichkeit, die für m_bShutdownRequested direkt nach dem waitForConnection prüft arbeiten konnte.

Während des Herunterfahren stellen Sie den Bool. Danach senden Dummy-Nachrichten an alle vorhandenen Rohrleitungen, so dass sie die Verbindung und überprüfen Sie die Bool und Abfahren sauber öffnen.

Eine einfache und einfache Lösung ist ein Dummy-Client erstellen und eine Verbindung mit dem Server tun.

NamedPipeServerStream pServer;
bool exit_flg=false;
    public void PipeServerWaiter()
{

    NamedPipeServerStream  pipeServer = new NamedPipeServerStream("DphPipe", PipeDirection.InOut, NamedPipeServerStream.MaxAllowedServerInstances);
    pServer = pipeServer;
    pipeServer.WaitForConnection();


    if (exit_flg) return;
    thread = new Thread(PipeServerWaiter);
    thread.Start();

}
public void Dispose()
{
    try
    {
        exit_flg = true;
        NamedPipeClientStream clt = new NamedPipeClientStream(".", "DphPipe");
        clt.Connect();
        clt.Close();

        pServer.Close();
        pServer.Dispose();


    }
using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Pipes;
using System.Threading;
using System.Windows;
using System.Windows.Controls;

namespace PIPESERVER
{
    public partial class PWIN : UserControl
   {
    public string msg = "", cmd = "", text = "";
    public NamedPipeServerStream pipe;
    public NamedPipeClientStream dummyclient;
    public string PipeName = "PIPE1";
    public static string status = "";
    private static int numThreads = 2;
    int threadId;
    int i;
    string[] word;
    char[] buffer;
    public StreamString ss;

    public bool ConnectDummyClient()
    {
        new Thread(() =>
        {
            dummyclient = new NamedPipeClientStream(".", "PIPE1");
            try
            {
                dummyclient.Connect(5000); // 5 second timeout
            }
            catch (Exception e)
            {
                Act.m.md.AMsg(e.Message); // Display error msg
                Act.m.console.PipeButton.IsChecked = false;
            }
        }).Start();
        return true;
    }

    public bool RaisePipe()
    {
        TextBlock tb = Act.m.tb;
        try
        {
            pipe = new NamedPipeServerStream("PIPE1", PipeDirection.InOut, numThreads);
            threadId = Thread.CurrentThread.ManagedThreadId;
            pipe.WaitForConnection();
            Act.m.md.Msg("Pipe Raised");
            return true;
        }
        catch (Exception e)
        {
            string err = e.Message;
            tb.Inlines.Add(new Run("Pipe Failed to Init on Server Side"));
            tb.Inlines.Add(new LineBreak());
            return false;
        }
    }

    public void ServerWaitForMessages()
    {
        new Thread(() =>
        {
            cmd = "";
            ss = new StreamString(pipe);
            while (cmd != "CLOSE")
            {
                try
                {
                    buffer = new char[256];
                    text = "";
                    msg = ss.ReadString().ToUpper();
                    word = msg.Split(' ');
                    cmd = word[0].ToUpper();
                    for (i = 1; i < word.Length; i++) text += word[i] + " ";
                    switch (cmd)
                    {
                        case "AUTHENTICATE": ss.WriteString("I am PIPE1 server"); break;
                        case "SOMEPIPEREQUEST":ss.WriteString(doSomePipeRequestReturningString()):break;
                        case "CLOSE": ss.WriteString("CLOSE");// reply to client
                            Thread.Sleep(1000);// wait for client to pick-up shutdown message
                            pipe.Close();
                            Act.m.md.Msg("Server Shutdown ok"); // Server side message
                            break;
                    }
                }
                catch (IOException iox)
                {
                    string error = iox.Message;
                    Act.m.md.Msg(error);
                    break;
                }
            }
        }).Start();
    }

    public void DummyClientCloseServerRequest()
    {
        StreamString ss = new StreamString(dummyclient);
        ss.WriteString("CLOSE");
        ss.ReadString();
    }

// Usage, Place ToggleButtons innerhalb Stackpanel, und sie im Code zurück also:

private void PipeButton_Checked(object sender, RoutedEventArgs e)
    {
        Act.m.pwin.ConnectDummyClient();
        Act.m.pwin.RaisePipe();
    }
private void PipeButton_Unchecked(object sender, RoutedEventArgs e)
    {
        Act.m.pwin.DummyClientCloseServerRequest();
        Act.m.console.WaitButton.IsChecked = false;
        Keyboard.Focus(Act.m.md.tb1);
    }
private void WaitButton_Checked(object sender, RoutedEventArgs e)
    {
        Act.m.pwin.Wait();
    }
private void WaitButton_Unchecked(object sender, RoutedEventArgs e)
    {
    }

// wie ein Charme für mich. Hochachtungsvoll, zzzbc     }

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top