2010-08-20 3 views
0

는 .NET 2.0 다음 ​​시나리오를 고려하시기 바랍니다 잠재적 인 비 스레드 안전 이벤트를 처리하는 가장 좋은 방법은 무엇입니까. 그러면 구독자는 이벤트를 받으면 항목을 Windows.Forms.Listbox에 추가합니다. 이로 인해 스레드 간 예외가 발생합니다.

제 질문은 이러한 상황을 처리하는 가장 좋은 방법입니다.

private delegate void messageDel(string text); 
private void ThreadSafeMsg(string text) 
{ 
    if (this.InvokeRequired) 
    { 
    messageDel d = new messageDel(ThreadSafeMsg); 
    this.Invoke(d, new object[] { text }); 
    } 
    else 
    { 
    listBox1.Items.Add(text); 
    listBox1.Update(); 
    } 
} 

// event 
void Instance_Message(string text) 
{ 
    ThreadSafeMsg(text); 
} 

이 그물 2에서이 문제를 처리 할 수있는 최적의 방법입니다 다음과 같이 내가 함께 온 솔루션은 무엇입니까? 무엇에 대해. NET 3.5?

답변

1

, 당신은 항상을 알고 참조하십시오. Elapsed 이벤트는 스레드 풀 스레드에서 발생합니다. never UI 스레드.

System.Timers.Timer를 사용하는 것이 무의미한 이유는 System.Windows.Forms.Timer를 사용하기 만하면됩니다. Control.Begin/Invoke를 사용하면 원숭이가 필요 없습니다. 사용자가 양식을 닫는 것처럼 이벤트가 발생하면 ObjectDisposedException을 사용하여 프로그램을 중단 할 수 없습니다.

+0

Forms.Timer를 사용하여 포인터를 주셔서 감사합니다 ... 나는 심지어 존재하지 않았다는 것을 알고있었습니다. – fishhead

+0

도구 상자에 있습니다. –

1

UI 스레드 외부에서 항목에 액세스하려고하기 때문에 크로스 스레드 예외가 있습니다. 대리인은 메시지 펌프에 연결하여 UI를 변경해야합니다.

양식 타이머를 사용하면 UI 스레드에있게됩니다. 그러나 BackgroundWorkerThread를 사용하는 경우 동일한 문제가 발생하며 여기에도 대리인이 필요합니다.

는 Control.InvokeRequired를 사용하여 아무 문제가 없다 Threading in Windows Forms

1

닷넷 3.5와 거의 동일합니다. 다른 작업 스레드에서 UI 스레드에 액세스 할 때 Windows Forms 및 크로스 스레딩과 관련되어 있기 때문입니다. 그러나 일반 작업 <> 및 Func <>을 사용하여 코드를 더 작게 만들 수 있으므로 대리인을 수동으로 만들지 않아도됩니다. 이 같은

뭔가 :

private void ThreadSafeMsg(string text) 
{ 
    if (this.InvokeRequired) 
     this.Invoke(new Action<string>(ThreadSafeMsg), new object[] { text }); 
    else 
    { 
     // Stuff... 
    } 
} 
0

귀하의 경우 가장 쉬운 솔루션 - (이 솔루션을 System.Windows.Forms.Timer 클래스를 사용하지만, 일반적인 경우가 아닌 GUI 스레드에서 당신에게 GUI-물건을 액세스하기 위해 다음과 같은 솔루션을 사용할 수 있습니다) .NET 2.0에 적용하지만, .NET 3.5이 더 우아한 :

public static class ControlExtentions 
{ 
    public static void InvokeIfNeeded(this Control control, Action doit) 
    { 
     if (control.InvokeRequired) 
      control.Invoke(doit); 
     else 
      doit(); 
    } 
} 

그리고 당신은 UI에서 다음과 같이 어떤 스레드로부터 이잖아요, 그것을 사용하지 않거나 서로 :

this.InvokeIfNeeded(()=> 
    { 
    listBox1.Items.Add(text); 
    listBox1.Update(); 
    }); 
0

어떤 작업을 수행 하느냐에 따라 Control.BeginInvoke가 Control.Invoke보다 낫습니다. Control.Invoke는 반환하기 전에 UI 스레드가 메시지를 처리 ​​할 때까지 대기합니다. UI 스레드가 차단되면 영원히 기다립니다. Control.BeginInvoke는 UI 스레드에 대한 메시지를 대기열에 추가하고 즉시 반환합니다. BeginInvoke를 시도하기 바로 전에 컨트롤이 처리되면 예외를 피할 수있는 방법이 없으므로 예외를 잡을 필요가 있습니다 (타이밍에 따라 ObjectDisposedException 또는 IllegalOperationException 일 수 있음). 또한 메시지를 게시 할 때 플래그 나 카운터를 설정해야하며 메시지 처리기에서 메시지를 지우거나 줄일 수 있어야합니다 (Threading.Interlocked를 사용하는 것이 좋습니다).증가/감소) UI 스레드가 차단 된 상태에서 너무 많은 수의 메시지를 대기열에 넣지 않도록합니다.