2009-09-22 2 views
4

상당히 복잡한 멀티 스레드 Windows 서비스가 작동하지만 올바르게 정리하는 방법을 알 수 없습니다. 아래는 내가 가지고있는 것을 보여주는 몇 가지 [의사] 코드입니다. 실제 코드는 훨씬 복잡하고 복사/붙여 넣기에는 너무 많습니다.스레드를 사용하여 클래스를 올바르게 처리 함

기본적으로 작업을 수행 할 스레드를 만드는 클래스 요청이 있습니다. 리스너에 새 요청이 들어 오면 프로세서로 보내어 새 요청을 만들고 요청 목록을 유지 관리합니다. 서비스가 중지되면 목록의 모든 요청을 정리합니다. 그러나 요청 작업이 완료되면 클래스의 한 인스턴스를 정리하는 방법은 무엇입니까?

도움 주셔서 감사합니다.

넬슨

class Service 
{ 
    Listener listener; 
    Processor processor; 

    OnStart() 
    { 
    processor = new Processor(); 
    listener = new Listener(processor); 
    } 

    OnStop() 
    { 
    listener.Dispose(); 
    processor.Dispose(); 
    } 
} 

class Listener 
{ 
    Thread thread; 
    bool terminate = false; 

    Listener(Processor processor) 
    { 
    thread = new Thread(DoWork); 
    thread.Start(processor); 
    } 

    DoWork(Processor processor) 
    { 
    WaitForConnection(NewConnection); 
    } 

NewConnection(String data) 
{ 
    processor.NewRequest(data); 

    if (terminate) 
     return; 

    WaitForConnection(NewConnection); 
} 

    Dispose() 
    { 
    terminate = true; 
    thread.Join(); 
    } 
} 

class Processor 
{ 
    //I need to maintain this list so that when the service stops I can cleanly close down 
    List<Request> requests = new List<Request>(); 

    NewRequest(string data) 
    { 
    request.Add(new Request(data)); 
    } 

    Dispose() 
    { 
    //Cleanup each request 
    foreach (Request request in requests) 
    { 
     request.Dispose(); 
    } 
    } 
} 

class Request 
{ 
    Thread thread; 
    bool terminate; 

    Request(string data) 
    { 
    while (true) 
    { 
     //Do some work 
     Thread.Sleep(1000); 

     if (doneWorking) 
     break; 

     if (terminate) 
     return; 
    } 

    //We're done. If I return this thread stops. But how do I properly remove this Request instance from the Processor.requests list? 
    } 

    Dispose() 
    { 
    terminate = true; 
    thread.Join(); 
    } 
} 

답변

3

이 거친 스케치입니다 :

delegate void CompletedRequest(Request req); 

class Processor : ITrackCompletion 
{ 
    //I need to maintain this list so that when the service stops I can cleanly close down 
    List<Request> requests = new List<Request>(); 

    public void NewRequest(string data) 
    { 
     lock(requests) 
      request.Add(new Request(data), Complete); 
    } 

    public void Complete(Request req) 
    { 
     lock (requests) 
      requests.Remove(req); 
    } 

    public void Dispose() 
    { 
     //Cleanup each request 
     foreach (Request request in requests.ToArray()) 
     { 
      request.Dispose(); 
     } 
    } 
} 

class Request 
{ 
    Thread thread; 
    bool terminate; 

    public Request(string data, CompletedRequest complete) 
    { 
     try 
     { 
      while (true) 
      { 
       //Do some work 
       Thread.Sleep(1000); 

       if (doneWorking) 
        break; 

       if (terminate) 
        return; 
      } 
     } 
     finally 
     { 
      //We're done. If I return this thread stops. But how do I properly remove this Request instance from the Processor.requests list? 
      complete(this); 
     } 
    } 

    void Dispose() 
    { 
     terminate = true; 
     thread.Join(); 
    } 
} 
+0

그것은 기본적으로 내가 지금 가지고있는 것입니다. 확인해 주셔서 감사합니다. 왜 당신은 요청을합니까? 배열()? 잠금을 피할 수있을 정도입니까? 어떤 방식 으로든 더 빠르고 안전합니까? 감사. –

+0

안전하고 성능이 좋습니다 ... 다른 스레드가 내 목록에서 제거하므로 잠글 수 없습니다. 목록을 잠그면 Join()이 완료되지 않습니다. 잠금이 설정된 상태에서 함수를 호출하지 않는 것이 가장 좋습니다. 또한 컬렉션이 수정되고 foreach 루프에서 예외가 발생하므로 잠금을 무시할 수 없습니다. –

+0

코드의 다른 부분에서 직접 경험했습니다. 나는 그것이 교착 상태 때문에 발생했다는 것을 알았지 만, 당신 덕분에 쉽게 해결할 수있었습니다. –

4

하나의 가능성은 대리인의 형태로 요청에 콜백을 전달하는 것입니다 : "당신이 처리를 완료 한 때, 나에게 다시 전화 해". 그런 다음 요청 처리가 끝나면 콜백을 실행하고 정리를 처리하게하십시오.

한 가지주의해야 할 사항 : 목록을 처리하려고 시도한 다음 다른 스레드의 목록에서 항목을 제거하려고하면 문제가 발생합니다. 아마 thread-safe 한 방법으로 액세스되는 플래그를 유지해야하고 목록의 모든 것을 처리하기 시작하면 얻은 콜백을 무시하십시오.

+0

이 프로세서의 특정 인스턴스에 묶여 대리인인가? 즉, 여러 인스턴스의 프로세서를 만들고 대리자를 호출하면 해당 인스턴스를 올바른 목록으로 사용합니까? (프로세서의 메서드에 대한) Request에 대리자를 전달하면 어떻게됩니까? 그렇다면 그건 제가 놓친 것입니다. 나는이 메서드를 가지고 있었지만 위임자 였지만 클래스간에 직접 대리자를 사용할 수는 없었습니다. –

+0

스레드 안전성에서 단순히 lock()으로 문제를 해결하지 않았습니까? 목록에서 하나의 항목을 제거하려고하면 Dispose()가 나를 때리면 foreach는 항목을 찾지 못합니다. 그 반대의 경우 항목이 제거 된 다음 Dispose()가 나머지를 정리합니다. 이 모든 것을 시도해보고 알려 드리겠습니다. 다시 한번 감사드립니다. –

+0

전체'foreach' 루프를 잠글 필요가 있습니다. 실제로 사용하지 않을 것입니다. 끝내면 더 이상 신경 쓰지 않아도됩니다. 델리게이트가 얼마나 구체적인지를 정확하게 결정할 수 있습니다. 예를 들어, 각 개별 요청에 따라 다를 수 있습니다. 익명 메서드 또는 람다식이 여기서 도움이 될 수 있습니다. –

관련 문제