2011-04-25 4 views
6

내 이해는 Thread.Abort가 차단 된 스레드에서 ThreadAbortException을 발생시켜야한다는 것이지만 TcpListener.AcceptSocket을 처리 할 때는 그렇지 않습니다. 여기에 문제의 가장 기본적인 그림입니다 :AcceptSocket은 Thread.Abort 요청을 준수하지 않습니다.

class Program 
{ 
    static void Main(string[] args) 
    { 
     Thread thread = new Thread(Listen); 
     thread.Start(); 
     Thread.Sleep(1000); // give it a second to get going 
     Console.WriteLine("Aborting listener thread"); 
     thread.Abort(); 
     thread.Join(); 
     Console.WriteLine("Listener thread finished press <enter> to end app."); 
     Console.ReadLine(); 
    } 
    static void Listen() 
    { 
     try 
     { 
      Console.WriteLine("Starting to listen"); 
      TcpListener listener = new TcpListener(IPAddress.Any, 4070); 
      listener.Start(); 
      Socket socket = listener.AcceptSocket(); 
      Console.WriteLine("Connected!"); 
      return; 
     } 
     catch (ThreadAbortException exception) 
     { 
      Console.WriteLine("Abort requested"); 
     } 
    } 
} 

thread.Abort() 호출이 AcceptSocket을 중지하고 ThreadAbortException 핸들러를 실행한다. Howerver 이것은 일어나지 않습니다.

대신 BeginAcceptSocket를 호출 ListenAsync에 대한 AcceptSocket 내 들어 래퍼 스와핑 : 그것은 "표시"이 경우

static void ListenAsync() 
    { 
     try 
     { 
      ManualResetEvent clientConnected = new ManualResetEvent(false); 

      Console.WriteLine("Starting to listen"); 
      TcpListener listener = new TcpListener(IPAddress.Any, 4070); 
      listener.Start(); 
      clientConnected.Reset(); 
      var iasyncResult = listener.BeginAcceptSocket((ar) => 
      { 
       Socket socket = listener.EndAcceptSocket(ar); 
       Console.WriteLine("Connected!"); 
       clientConnected.Set(); 
      }, null); 
      clientConnected.WaitOne(); 

      return; 
     } 
     catch (ThreadAbortException exception) 
     { 
      Console.WriteLine("Abort requested"); 
     } 
    } 

를 잘 작동합니다. thread가 WaitOne를 실행하고있는 동안에 ThreadAbortException가 캐치됩니다. 그러나이 BeginAcceptSocket에 대한 호출에 의해 생성 된 스레드가 계속 실행 및 소켓을 받아 들일 수있다 마지막으로

(I 텔넷와 해당 포트를 열어이 문제를 확인), 나는 TheadAbortException 핸들러의 일부가 시도로 Listener.Stop 추가 EndAcceptSocket 호출을 따라 잡으십시오 (소켓은 Stop으로 처리되기 때문에)

소켓 연결을 수신하는 프로세스를 시작하고 중지하는 가장 좋은 방법입니까?

+0

스레드를 죽이면 clientConnected 이벤트는 어떻게됩니까? 왜 물건을 버리는 거니? 한 번 받아 들인 소켓으로 무엇을합니까? –

+0

'Thread.Abort'는 거의 항상 더러운 해킹이므로 피해야합니다. 너의 실이 우아하게 끝나게해라 ... 그 밑에있는 깔개를 잡아 당기지 마라. – spender

답변

7

Thread.Abort이 소켓에서 수신 대기중인 스레드를 중단하지 않는 이유는 해당 스레드가 listen() 커널 호출 내부에서 차단 되었기 때문입니다. ThreadAbortException은 CLR이 실제로 실행될 때 CLR에 의해 발생 될 수 있으며 listen 스레드에 대한 호출 중에 실제로 관리되지 않는 시스템 호출 내부에 고정되어 있습니다. listen에 대한 호출이 반환되고 CLR 내에서 실행이 다시 시작되면 스레드 중단을 계속할 수 있습니다.

두 번째는 Thread.Abort()을 사용하지 말라고 조언합니다. 해당 경로로 이동하기로 결정한 경우 두 번째 예와 비슷한 기술을 사용할 수 있습니다. 그러나 스레드 리스너를 종료하려면 다른 방법을 사용하고 Listener.Stop()을 호출하는 것이 좋습니다.

+1

Thead에 어떤 문제가 있는지 잘 모르겠습니다.(), 그러나 나는 조언에 귀 기울이며 기꺼이 다른 옵션을 조사 할 것입니다. –

+3

@Ralph : 광범위한 관점에서 'Thread.Abort'는 다음과 같은 이유로 문제가 있습니다 : a) (여기에서 보았 듯이) 대상 스레드가 즉시 중단되거나 (심지어는 곧 * 중단 될 수도 있지만) CLR은 관리되지 않는 코드를 사용하며, b) 파괴적이며 스레드가 중단 될 때 스레드의 상태를 알려주지 않습니다. 가능한 경우 취소/중단 플래그를 사용하고 제한 시간이있는 차단 방법을 사용할 것을 강력히 권장합니다. 이렇게하면 취소 플래그를 확인하고 그 당시 적절한 정리 (있는 경우)를 수행 할 수 있습니다. –

관련 문제