2008-09-04 6 views
11

내가 쓰고 싶은 코드에서 예외를 throw위한 C#에서 좋은 방법이 있나요은 다음과 같이이다 : 나는 스레드 B가 주기적으로 확인 할 수 있습니다 알고주어진 스레드

void MethodOnThreadA() 
{ 
    for (;;) 
    { 
     // Do stuff 
     if (ErrorConditionMet) 
      ThrowOnThread(threadB, new MyException(...)); 
    } 
} 

void MethodOnThreadB() 
{ 
    try 
    { 
     for (;;) 
     { 
      // Do stuff 
     } 
    } 
    catch (MyException ex) 
    { 
     // Do the right thing for this exception. 
    } 
} 

, 스레드 안전한 방법으로 , 플래그가 스레드 A에 의해 설정되었는지 확인하지만 코드가 복잡해집니다. 내가 사용할 수있는 더 나은 메커니즘이 있습니까? 여기

주기적으로 점검을보다 구체화 예입니다

Dictionary<Thread, Exception> exceptionDictionary = new Dictionary<Thread, Exception>(); 

void ThrowOnThread(Thread thread, Exception ex) 
{ 
    // the exception passed in is going to be handed off to another thread, 
    // so it needs to be thread safe. 
    lock (exceptionDictionary) 
    { 
     exceptionDictionary[thread] = ex; 
    } 
} 

void ExceptionCheck() 
{ 
    lock (exceptionDictionary) 
    { 
     Exception ex; 
     if (exceptionDictionary.TryGetValue(Thread.CurrentThread, out ex)) 
      throw ex; 
    } 
} 

void MethodOnThreadA() 
{ 
    for (;;) 
    { 
     // Do stuff 
     if (ErrorConditionMet) 
      ThrowOnThread(threadB, new MyException(...)); 
    } 
} 

void MethodOnThreadB() 
{ 
    try 
    { 
     for (;;) 
     { 
      // Do stuff 
      ExceptionCheck(); 
     } 
    } 
    catch (MyException ex) 
    { 
     // Do the right thing for this exception. 
    } 
} 
+0

와우 오, 당신이 그것을 가능 예외가 발생되는 경우에도 간단한 추가에 볼 것으로 예상한다 :로

으로 간단한. – Dykam

답변

10

이 스레드에서 예외를 throw 좋은 생각

This article talks about ruby's timeout library. 아닙니다.

그런 일이 근본적으로 어떻게되는지 설명합니다. 루비에서 깨진 것이 아니라 어디서나 깨져서 스레드간에 예외가 발생합니다. 간단히 말해서

, 무엇을 (그리고 않습니다) 일어날 수있는 것은 이것이다 :

At some random time, throw an exception on thread B: 

ThreadB :

ThreadA

try { 
    //do stuff 
} finally { 
    CloseResourceOne(); 
    // ThreadA's exception gets thrown NOW, in the middle 
    // of our finally block and resource two NEVER gets closed. 
    // Obviously this is BAD, and the only way to stop is to NOT throw 
    // exceptions across threads 
    CloseResourceTwo(); 
} 

귀하의 '정기 검사'예로, 괜찮습니다 실제로 스레드간에 예외가 발생하지는 않습니다.
"다음에이 플래그를 볼 때 예외가 발생합니다"라는 플래그를 설정하는 중입니다. "catch 또는 finally 블록의 중간에 throw 될 수 있습니다." 문제.
그러나 이것을 수행하려는 경우 "exitnow"플래그를 설정하고이를 사용하여 예외 객체를 생성하는 번거 로움을 줄일 수 있습니다. 휘발성 bool은 정상적으로 작동합니다.

10

스레드와 좋아하는 것을 중단 같은 다른 메커니즘에 의해 스레드에서 발생 될 수있다 예외 충분히 문제가 다른 찾을 것이있다 그것을하는 방법.

예외는 처리 할 수없는 예외적 인 경험이 있음을 알리는 데 사용되는 메커니즘입니다. 뭔가 다른 것을이 예외적으로 경험했음을 알리기 위해 예외가 사용되도록 코드를 작성하지 않도록해야합니다.

다른 스레드는 코드으로 던져 질 수있는 모든 경우에 예외 을 처리하는 방법을 알지 못할 것입니다.

즉, 예외를 사용하는 것보다 스레드를 중단시키는 다른 메커니즘을 찾아야합니다.

이벤트 객체 또는 유사한 것을 사용하여 스레드에게 처리를 중단하도록 지시하는 것이 가장 좋은 방법입니다.

0

왜 이렇게하고 싶은지 알고 싶습니다. 좋은 습관이 아니기 때문에 쉬운 방법이 아닙니다. 당신은 아마 당신의 디자인으로 돌아가서 최종 목표를 달성하기위한 더 깨끗한 방법을 찾아야 할 것입니다.

0

나는 좋은 생각이라고 생각하지 않습니다 .. 이 문제에서 또 다른 균열이 있습니다. 공유 데이터와 같은 다른 메커니즘을 사용하여 스레드간에 신호를 보내보십시오.

0

다른 사람들과 마찬가지로 좋은 생각 인 것 같습니다.하지만 정말로하고 싶다면 SynchronizationContext의 하위 클래스를 만들어 게시하고 대상 스레드에 대리인을 보낼 수 있습니다 (해당되는 경우 그런 하위 클래스가 이미 존재하므로 WinForms 스레드가 작업이 완료됩니다.) 대상 스레드는 대리자를 받기 위해 메시지 펌프를 구현해야합니다.

0

@Orion 에드워즈는

나는 예외가 finally 블록에 던져 것에 대해 요점을.

그러나이 방법을 사용하여 다른 예외를 사용하는 방법이 있다고 생각합니다.

스레드 A :

At some random time, throw an exception on thread C: 

스레드 B는 :

try { 
    Signal thread C that exceptions may be thrown 
    //do stuff, without needing to check exit conditions 
    Signal thread C that exceptions may no longer be thrown 
} 
catch { 
    // exception/interrupt occurred handle... 
} 
finally { 
    // ...and clean up 
    CloseResourceOne(); 
    CloseResourceTwo(); 
} 

스레드 C :

while(thread-B-wants-exceptions) { 
     try { 
      Thread.Sleep(1) 
     } 
     catch { 
      // exception was thrown... 
      if Thread B still wants to handle exceptions 
       throw-in-B 
     } 
    } 

또는은 바보이다? 또 다른 문제를 연구, 당신의 질문을 생각 나게이 문서를 건너 왔어요 동안

1

오리온 에드워즈 (Orion Edwards)가 말하는 것은 완전히 사실이 아닙니다. "유일한"방식은 아닙니다. C#에서 CER를 사용

// Obviously this is BAD, and the only way to stop is to NOT throw 
// exceptions across threads 

(제한된 실행 영역)는 스레드 간 예외에서 코드를 보호 원자 작업으로 자원을 해제 할 수 있습니다. 이 기술은 Windows의 네이티브 API에서 작동하는 .NET Framework의 여러 클래스에서 사용되는데, 릴리스되지 않은 핸들로 인해 메모리 누수가 발생할 수 있습니다.

다음 예 확실 PrepareConstrainedRegions 방법을 사용하여 핸들을 설정하는 방법을 도시 http://msdn.microsoft.com/en-us/library/system.runtime.compilerservices.runtimehelpers.prepareconstrainedregions.aspx

참조. 지정된 기존 핸들에 핸들을 안정 적으로 설정하려면 SafeHandle 오브젝트 내에서 원시 핸들을 할당하고 그 핸들을 연속적으로 기록하는 것이 원자 적이어야합니다. 이러한 작업 (예 : 스레드 중단 또는 메모리 부족 예외)간에 실패가 발생하면 네이티브 핸들이 유출됩니다. PrepareConstrainedRegions 메서드를 사용하여 핸들이 누수되지 않았는지 확인할 수 있습니다. 그것이 가능했던 경우

public MySafeHandle AllocateHandle() 
{ 
    // Allocate SafeHandle first to avoid failure later. 
    MySafeHandle sh = new MySafeHandle(); 

    RuntimeHelpers.PrepareConstrainedRegions(); 
    try { } 
    finally // this finally block is atomic an uninterruptible by inter-thread exceptions 
    { 
     MyStruct myStruct = new MyStruct(); 
     NativeAllocateHandle(ref myStruct); 
     sh.SetHandle(myStruct.m_outputHandle); 
    } 

    return sh; 
}