2013-08-29 1 views
5

나는 ManualResetEvent를 사용하여 스레드를 동기화하는 응용 프로그램을 사용하고 있습니다. FxCop이 그 물건들을 처분하라고 나에게 말했다. 나는 나에게 같은 말 다음의 논의 발견ManualResetEvent는 언제 폐기되어야합니까?

Do I need to Dispose() or Close() an EventWaitHandle?

을 그러나으로 ManualResetEvent의 인스턴스를 처리 할 때 나도 몰라.

private void btn_Click(object sender, EventArgs e) 
{ 
    var mre = new ManualResetEvent(false); 
    new Thread(() => this.SetEvent(mre)).Start(); 
    for (int i = 0; i < 10; ++i) 
    { 
     new Thread(() => this.WaitFor(mre)).Start(); 
    } 
} 

private void SetEvent(ManualResetEvent manualResetEvent) 
{ 
    Thread.Sleep(10000); 
    manualResetEvent.Set(); 
} 

private void WaitFor(ManualResetEvent manualResetEvent) 
{ 
    manualResetEvent.WaitOne(); 
} 

문제는으로 ManualResetEvent의 여러 인스턴스가 존재하고 여러 스레드가 각 인스턴스을 기다리고 있다는 것입니다 :

다음의 간단한 코드는 문제를 보여줍니다.

내가 인스턴스를 목록에 외우면 나는 언제 폐기할지 모른다. WaitOne() 호출 후에 처리하면 호출이 여러 번 처리되고 다른 스레드가 여전히 대기하는 동안 처 리됩니다.

이벤트를 생성 한 스레드에는 이벤트에 대한 참조가 없습니다. 이 MRE를 기다리는 다른 스레드가 있기 때문에 setter-thread는이를 처리해서는 안됩니다. 대기중인 각 스레드는 앞서 언급 한 것처럼 처리 할 수 ​​없습니다.

그래서 질문입니다.이 ManualResetEvent를 언제 폐기해야합니까?

+1

코드는 무의미하며 MRE의 인스턴스가 하나만 * 있습니다. 메서드의 끝에 그것을 처리하는 것은 괜찮습니다. –

+1

아니, 그렇게 생각하지 않아.MRE를 생성하는 코드는 버튼 클릭 이벤트 핸들러입니다. 여러 MRE를 생성하는 여러 번 클릭 할 수 있습니다. 위의 코드는 단순화되었습니다. 메서드가 완료된 후에이 MRE를 사용하는 스레드가 11 개 있기 때문에이 메서드 끝에서 MRE를 삭제하면 작동하지 않습니다. setter-thread는 10 초를 대기하고 다른 10 개의 스레드가이 MRE를 기다리고 있습니다. –

답변

5

ManualResetEvent은 더 이상 필요하지 않을 때 처리해야합니다. 당신의 진정한 질문은 "내가 더 이상 그것을 필요로하지 않는다는 것을 어떻게 알 수 있습니까?"

스레드가 완료되면 일반적으로 알림이 표시되고 스레드에서 Join을 호출합니다. 또는 스레드가 완료되었음을 나타내는 이벤트를 설정합니다. 스레드가 여러 개인 경우 모두 CountdownEvent이라고 알릴 수 있습니다. 스레드 알림을 관리하는 몇 가지 다른 방법이 있습니다.

리소스를 할당하는 경우 리소스가 올바르게 배치되었는지는 사용자가 결정해야합니다. 위의 코드에서 어떤 스레드가 실행 중인지 또는 어떤 스레드가 연관되어 있는지 추적 할 방법이 없습니다. ManualResetEvent. MRE가 올바르게 폐기되었는지 확인하려면 MRE를 추적 할뿐만 아니라 어떤 스레드가이 스레드를 사용하고 있는지, 어떤 스레드가 작업을 완료했는지 추적해야합니다. 쓰레드를 처리 할 수 ​​있도록 스레드가 완료되었습니다.

이런 상황에서 정말로 MRE를 사용해야하는 경우 스레드와 MRE에 대한 참조를 포함하는 데이터 구조를 만들고 CountdownEvent 스레드가 완료되면 신호를 보냅니다. 같은 뭔가 :

이제
class WorkUnit 
{ 
    public List<Thread> Threads; 
    public ManualResetEvent MRE; 
    public CountdownEvent CE; 
} 

, 쓰레드가이 수행 완료 :

workUnit.CE.Signal(); 

프로그램 (아마 메인 스레드)의 일부 다른 부분이 주기적으로 작업 단위의 목록을 확인합니다. 이 목록의 각 항목에 대해 그것은이 수행합니다

if (workUnit.CE.WaitOne(0)) 
{ 
    foreach (Thread t in workUnit.Threads) 
    { 
     t.Join(); 
    } 
    // dispose the MRE and the CE 
    // and remove the work unit from the list 
} 

예, 그것은 많은 일입니다. 이런 종류의 일을 할 필요가 없도록 프로그램을 구성 할 수 있다면 가장 좋습니다.

+0

감사합니다. 유일한 문제는 얼마나 많은 스레드가 MRE를 기다리는 지 모르기 때문에 CountDownEvent를 초기화 할 수없는 이유입니다. 그러나 MRE가 더 이상 필요하지 않을 때를 알고있는 디자인을 고려해야한다는 것이 옳았습니다. 현재 일부 값을 계산하고 결과를 컨트롤에 표시하기 때문에 작업자 스레드의 끝을 기다리는 스레드가 없습니다. 그 후 작업 (예, 스레드 대신 작업을 사용하고 있습니다. 그렇지만 작업이 ContinueWith를 사용하여 CountDownEvent를 설정할 수 있기 때문에 문제가 여전히 동일하다고 생각합니다.) 그리고 명시 적으로 기다리는 코드가 없습니다. –

+0

내 경우에 대한 해결책을 찾았습니다. setter-thread는 MRE를 리턴하는 하나의 메소드에서만 작성되고 시작됩니다. 이 메서드의 호출자는 MRE를 알고 다중 스레드로 전파하지만 수신자를 알고 있습니다. MRE 수신자를 관리하고 끝날 때까지 기다리는 처리기 객체에 MRE를 래핑 할 수 있습니다. 그 후 MRE는 공개 될 수 있습니다. 당신의 도움을 주셔서 감사합니다. –