2013. 11. 12. 14:00

WCF가 예전에 사용하던 방식과 달라 이것저것 테스트하다가 간만에 뜬 에러

 

크로스 스레드 작업이 잘못되었습니다.

아....

 

예전에 WPF에서 한번 소개 하긴 했었습니다만 윈폼에서는 약간 다르죠.

(참고 : [WPF] 다른 쓰레드에서 UI쓰레드 접근하기 - Dispatcher.Invoke)

 

연관글 영역

 

 

1. 일반적인 방법

일반적으로 인보크(Invoke)를 사용하려면 델리게이트(Delegate)를 만들어야 합니다.

(참고 : MSDN - Control.Invoke 메서드)

 

일반적인 방법에서는 다음과 같은 순서로 인보크를 사용합니다.

1) 델리게이트 선언

2) 델리게이트에 연결할 함수 생성

3) 델리게이트와 생성한 함수 연결

4) 인보크로 델리게이트 호출

//1) 델리게이트 선언 
/// <summary> 
/// 델리게이트 선언(연결 할 함수와 같은 모양이 되도록 만든다.) 
/// </summary> 
/// <param name="sData"></param> 
private delegate void DataDelegate(string sData);  
//2) 델리게이트에 연결할 함수 생성 
/// <summary> 
/// 실제 동작하는 함수(연결 할 함수) 
/// </summary> 
private void DelegteFuntion(string sData) 
{ 	label2.Text = sData; 
}  

//3) 델리게이트와 생성한 함수 연결 
//4) 인보크로 델리게이트 호출 
//사용할때
this.Invoke(new DataDelegate(DelegteFuntion), "Test!");

 

 

이 방법의 가장 큰 문제는 원하는 동작만큼 델리게이트를 선언해야 한다는 것입니다-_-;;;;; 

그래서 간소화 방법을 사용하죠.

 

 

2. 간소화 방법

간소화 방법은 일반적인 방법과는 달리 한 줄로 델리게이트를 선언하는 방법입니다.

메소드인보커 대리자(MethodInvoker Delegate)를 이용하는 방법이죠.

(참고 : MSDN - MethodInvoker 대리자)

this.Invoke(new Action(
    delegate () 
    { 
        label2.Text = "Test"; 
    }));  

//혹은
this.Invoke(new MethodInvoker( 	
    delegate() 	
    { 		
        label2.Text = "Test"; 	
    }));

 

깔끔하게 됐죠?

 

메소드인보커를 이용하면 델리게이트를 전역으로 선언하지 않고 사용할 수 있습니다.

단 해당 데리자를 따로 저장하지 않으면 1회만 사용할 수 있습니다.

 

 

3. 자신의 스레드인지 확인하기

하지만 자신의 스레드에서 인보크를 시도하면 에러가 납니다.

이걸 해결하려면 'InvokeRequired'속성을 써야 합니다.

'InvokeRequired'속성은 'System.Windows.Forms'에 속해있는 속성으로 호출된 메소드가 같은 스레드인지 아닌지 확인해 줍니다.

if (true == InvokeRequired)
{//다른 쓰래드다.
}
else
{//같은 쓰래드다.
}

 

다른 스레드일 때는 인보크를 해야 하고 같은 스레드일 때는 필요 없습니다. 

 

 

4. 공통화 함수

매번 'InvokeRequired'와 'Invoke'를 써가며 코드를 만드는 건 유지보수성이 떨어집니다.

아래 함수를 재사용하기 쉽도록 적절한 위치에 선언하여 사용합시다.

/// <summary>
/// 크로스 스레드 체크를 하고 상황에 맞게 처리한다.
/// </summary>
/// <param name="controlThis"></param>
/// <param name="action"></param>
public static void CrossThread_Winfom(Control controlThis, Action action)
{
    if (true == controlThis.InvokeRequired)
    {//다른 쓰래드다.
        controlThis.Invoke(new Action(
            delegate ()
            {
                action();
            }));
    }
    else
    {//같은 쓰래드다.
        action();
    }
}

 

 

마무리

테스트 프로젝트 : github - dang-gun/DotNetSamples/CrossThreadTest_Winfom

 

검색하다가 안 사실이지만 의외로 델리게이트를 간략화해서 쓰는 걸 모르시는 분들이 많으시군요.

액션 같은 것은 무명 메서드로 사용할 수 있으니 잘 활용해 봅시다.

 

제 기억으론 책에서도 나왔던 거 같은데;;;(아닌가?)

이럴 줄 알았으면 빨리 포스팅하는 거였는데 말이죠 ㅎㅎㅎㅎ