pipeserver#WaitforConnection에서 차단 된 스레드를 차단하는 좋은 방법은 무엇입니까?

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

  •  03-07-2019
  •  | 
  •  

문제

여러 스레드를 생성하는 응용 프로그램을 시작합니다. 각 스레드가 있는데, 각 스레드는 이름이 지정된 파이프 서버 (.NET 3.5 명명 된 파이프 IPC의 관리 유형)를 생성하고 클라이언트가 연결되기를 기다립니다 (블록). 코드는 의도 한대로 기능합니다.

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);
        ....  

이제이 프로세스를 깨끗하게 가져 오려면 종료 방법이 필요합니다. 나는 일반적인 bool flag isshutdownrequested 트릭을 시도했다. 그러나 Pipestream은 WaitforConnection () 호출에 차단되며 스레드는 죽지 않습니다.

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!");
   }
} 

가입은 절대 반환하지 않습니다.

내가 시도하지 않았지만 작동하는 옵션은 Thread.Abort를 호출하고 예외를 먹는 것입니다. 그러나 그것은 옳지 않다고 생각합니다. 어떤 제안도

2009-12-22 업데이트
이전에 게시하지 않아서 죄송합니다 .. 이것은 Kim Hamilton (BCL 팀)의 응답으로받은 것입니다.

인터럽트 가능한 대기 시대를 수행하는 "올바른"방법은 startwaitforconnection을 호출하고 콜백의 새 연결을 처리 한 다음 파이프 스트림을 닫아 연결 대기를 중지하는 것입니다. 파이프가 닫히면 endwaitforconnection은 콜백 스레드가 잡을 수있는 ObjectDisparedException을 던지고, 느슨한 끝을 정리하고, 깨끗하게 종료합니다.

우리는 이것이 일반적인 질문이어야한다는 것을 알고 있으므로, 우리 팀의 누군가가 곧 블로그를 계획하고 있습니다.

도움이 되었습니까?

해결책

비동기 버전으로 전환하십시오. BeginWaitForConnection.

완료되면 완료 핸들러가 전화 할 수 있도록 깃발이 필요합니다. EndWaitForConnection 예외를 흡수하고 종료합니다 (전화 끝 ... 자원을 정리할 수 있도록).

다른 팁

이것은 치즈 맛이지만, 제가 일하게 된 유일한 방법입니다. '가짜'클라이언트를 만들고 이름이 지정된 파이프에 연결하여 대기 시간을 지나가십시오. 매번 작동합니다.

또한 Thread.abort () 조차도이 문제를 해결하지 못했습니다.


_pipeserver.Dispose();
_pipeserver = null;

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

다음 확장 방법을 사용할 수 있습니다. 'ManualResetevent CancelEvent'를 포함시켜주십시오.이 이벤트를 다른 스레드에서 설정하여 대기 연결 방법이 지금 중단되어 파이프를 닫아야한다는 신호를 보낼 수 있습니다. M_BSHUTDOWNREQUESTED를 설정할 때는 chanceEvent.set ()를 포함시키고 종료는 상대적으로 우아해야합니다.

    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
    }

이 문제를 해결하기 위해이 확장 방법을 썼습니다.

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
}

작동 할 수있는 한 가지 방법은 WaitforConnection 직후 M_BSHUTDOWNEQUESTED를 확인하는 것입니다.

종료 과정에서 부를 설정하십시오. 그 후 기존의 모든 파이프에 더미 메시지를 보내서 연결을 열고 부울을 점검하고 깨끗하게 닫습니다.

가장 간단하고 쉬운 솔루션은 더미 클라이언트를 생성하고 서버와 연결하는 것입니다.

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();
    }

// 사용법, StackPanel 내부에 토글 부트 톤을 배치하고 코드로 백업하십시오.

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)
    {
    }

// 저에게 매력처럼 일했습니다. 정중하게, zzzbc}

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top