2012-03-16 2 views
2

스레드에서 관리되지 않는 리소스를 사용하는 클래스가 있고 사용하지 않을 때 잠자기 상태가 될 수도 있습니다. 나는 그것을 위해 dispose를 구현하고있다. 아래의 예제 코드를 보아라. (내 앱의 다운 된 버젼이다.) 나는 (TheThread.IsAlive()) 동안 추가했다. DestroySomeUnmangedResouces()가 실행되기 전에 처리 된대로 true로 설정할 수 있습니다. 나는 내가 한 일이 정확하다고 생각하지 않는다. 누군가가 더 나은 모델을 제안 할 수 있다면 감사 할 것이다.스레드에서 관리되지 않는 리소스를 제거합니다.

protected virtual void Dispose(bool disposing) 
{ 
    if (!disposed) 
    { 
     if (disposing) 
     { 
      //managed 
     } 

     //unmanged 
     _stopTheThread = true; 
     startTheThreadEvent.Set(); 
     while(TheThread.IsAlive()); 
    } 
    disposed = true; 
} 

private void TheThread() 
{ 
    while (!_stopTheThread) 
    { 
     if (state == State.Stopped) 
     { 
      // wait till a start occurs 
      startTheThreadEvent.WaitOne(); 
     } 
     switch (state) 
     { 
      case Init: 
       CreateSomeUnmangedResouces(); 
       break; 

      case Run:  
       DoStuffWithUnmangedResouces(); 
       break; 

      case Stop: 
       DestroySomeUnmangedResouces(); 
       break; 
     } // switch 
    } 
    // Release unmanaged resources when component is disposed 
    DestroySomeUnmangedResouces(); 
} 
+0

메인 클래스에도 Finalizer가있는 경우 GC에서이 살인입니다. –

+0

이 기능은 "while (TheThread.IsAlive());" 또는 다른 것? – integra753

+0

제목 앞에 "C# :"등을 붙이지 마십시오. 그것이 바로 태그입니다. –

답변

2

작업자 스레드가 종료 될 때까지 기다리는 것이 좋습니다. 이를 위해 스레드가 종료 될 때까지 차단할 Thread.Join()을 사용할 수 있습니다.

현재 작업 스레드가 살아있을 경우 설문 조사를하기 때문에 대기 스레드에서 100 % CPU를 먹고 있습니다. 덜 리소스를 많이 사용하는 변형은 적어도 시간 간격 (15ms) 동안 수면을 유지하는 스로틀 폴링입니다.

하지만 가장 좋은 방법은 조건이 충족 될 때 신호를 받고 스레드를 깨우는 동기화 프리미티브를 기다리는 것입니다. 그래서 .Join은 갈 길입니다.

+0

당신이 말하는 것을 보았으나 dispose 메서드에서 차단 메서드를 호출하는 것이 좋습니다. 이자형.g DoStuffWithUnmangedResouces()가 완료되는 데 5 분이 걸렸습니다. – integra753

+0

Thread.Join을 타임 아웃과 함께 사용할 수 있습니다. 그러나 당신이 기다리고 싶은지 여부는 당신에게 달려 있습니다. 어떤 경로를 선택하든 그 결과로 계속 살아야합니다 (다시 열려고하면 잠긴 리소스, 종료 시간이 매우 길거나 종료 할 때 교착 상태). 더 나은 것은 리소스와 리소스에 액세스하는 방법과 런타임 불변 조건을 제공하는 방법에 따라 다릅니다. –

1
private readonly ManualResetEvent _stopEvent = new ManualResetEvent(false); 
    private readonly ManualResetEvent _threadStoppedEvent = new ManualResetEvent(false); 
    private bool disposed; 
    private int checkInterval = 10;//ms 


    protected virtual void Dispose(bool disposing) 
    { 
     if (!disposed) 
     { 
      if (disposing) 
      { 
       //managed 
      } 

      //unmanged 
      _stopEvent.Set(); 
      _threadStoppedEvent.WaitOne(); 
     } 
     disposed = true; 
    } 

    private void TheThread() 
    { 
     CreateSomeUnmangedResouces(); 

     while (!_stopEvent.WaitOne(checkInterval)) 
     { 
      DoStuffWithUnmangedResouces(); 
     } 

     DestroySomeUnmangedResouces(); 

     _threadStoppedEvent.Set(); 
    } 

또는 스레드가 배경

가 아닌 경우 대신 _threadStoppedEvent의) Thread.join를을 (사용할 수 있습니다
1

스레드를 닦아내야한다 처분 전화 발신자 - 가장 좋은 방법은 그것을에 가입 호출하는 것입니다 알로이가 제안했다. 스레드가 결합되면 관리되지 않는 리소스가 삭제되어 호출자 스레드에서 발생할 수 있습니다. 예 :

protected virtual void 
    Dispose 
     (bool disposing) 
    { 
     if (!disposed) 
     { 
      if (disposing) 
      { 
       if(TheThread != null) 
       { 
        // send a signal to stop the thread. 
        _stopTheThread = true; 
        startTheThreadEvent.Set(); 

        // Join the thread - we could timeout here but it should be the 
        // responsibility of the thread owner to ensure it exits 
        // If this is hanging then the owning object hasn't terminated 
        // its thread 
        TheThread.Join(); 

        TheThread = null; 
       } 
      } 

      // Now deal with unmanaged resources! 
      DestroySomeUnmangedResouces(); 
     } 

     disposed = true; 
    } 

이 접근법의 한 가지 단점은 스레드가 결국 종료된다고 가정한다는 것입니다. 이 될 수 있습니다. 즉, 스레드를 중지하는 신호가 충분하지 않음을 의미합니다. Join에는 overloads이 있는데 여기에는 시간 초과가 포함되어있어 호출 스레드가 멈추는 것을 방지 할 수 있습니다 (위 코드 샘플의 주석 참조).

+0

그러면 TheThread.Join (Int32)을 사용해야한다고 생각합니다. 이것이 실패하면 (예외적 인 상황으로) 예외를 던지는 것이 합리적인 것처럼 보일 수 있습니까? – integra753

+0

가능합니다. MillisecondsTimeout 매개 변수로 지정된 시간이 경과 한 후 스레드가 종료되지 않은 경우 조인 (Int32)은 false를 반환합니다. – Jeb

+0

위의 방법을 사용하고 있지만 TheThread.Join()을 사용하여 이상한 결과를보고 있습니다. TheThread.Join()을 호출하면 주 스레드와 TheThread가 차단됩니다. TheThread에서 Join() 호출에 따라 디버그 코드가 출력되지 않으므로이 사실을 알 수 있습니다. TheThread.Join()에서 타임 아웃을 지정하면 실패하고 TheThread는 블로킹을 볼 수 있습니다. 이 문제가 발생하는 이유는 무엇입니까? – integra753

0

실행중인 스레드가 개체에 대한 직접 또는 간접적 인 강력한 참조를 보유하고있는 경우 이러한 참조는 개체가 가비지 수집 대상이되지 않도록합니다. 따라서 그러한 객체에 파이널 라이저를 가질 이유가 없습니다.

다른 특정 객체가 스레드가 다른 개체에 WeakReference을 유지하기위한 스레드, 그것은 유용 할 수 이외의 에 의해 유지되는 참고로, 그러나, 스레드는만큼 관련 될 경우, 다른 객체가 범위를 벗어나면 스스로 종료됩니다. 이 종료는 스레드가 주기적으로 IsAlive 속성 (WeakReference)을 확인하도록하거나 다른 개체에 스레드 종료를 알리는 종료자를 포함시켜 수행 할 수 있습니다. 그런 것들을 주기적으로 폴링하는 것은 어떤 의미에서는 어렵지만, 파이널 라이저를 사용하면 스레드의 종료를 어느 정도 촉진 할 수 있습니다. 폴링은 여전히 ​​더 나은 것으로 생각됩니다. 파이널 라이저가 스레드에게 뭔가를해야한다고 알리는 것은 가능하지만 그렇게하는 것이 적절할 때도 있지만 일반적으로 객체가 완성되었다는 사실은 아무도 신속한 정리에 지나치게 염려하지 않는다는 것을 의미합니다. 스레드가 종료되기 전에 몇 초의 지연을 추가하면 아마 아무런 상처를 입지 않을 것입니다.

관련 문제