2014. 11. 23. 13:31ㆍProgramming/C#
다른 Framework도 마찬가지겠지만, winform에서도 mainThread(메인 UI가 동작하는 부분) 이외의 Thread에서 control을 제어하려고 하면 크로스 스레드 문제가 발생한다. (MFC할 때는 별 문제 없었던거 같았는데 ㅠ_ㅠ)
항상 해도 지나면 까먹길래 이번 기회에 확실히 기록해 두려고 한다.
일단 아래와 같은 쓰레드에서 동작하는 코드가 있다고 치자.
public void Thread_Run(){
button1.Text = "테스트입니다.";
}
위의 코드는 쓰레드 상에서는 동작하지 않는다. 물론 메인 쓰레드에서는 잘 동작한다.
Winform에서는 메인 쓰레드 이외의 쓰레드에서 컨트롤을 건드릴 필요가 없다고 생각해서 쓰레드에서의 컨트롤 제어를 막아놓고 있다.
하지만 개발을 하다보면 어떻게 메인 쓰레드에서만 콘트롤 동작을 할 수 있겠는가?
쓰레드에서의 콘트롤 동작을 가능하게 하기 위해, delegate와 invoke를 사용한다.
delegate는 함수 포인트를 저장하고 있는 함수 대리자라고 생각하면 쉽고,
invoke는 그러한 함수 대리자를 안전하게 호출하기 위한 함수라고 생각하면 쉽다.
우선 따로 함수 포인터를 저장할 수 있는 delegate를 선언한다.
위의 코드에서 보면 해당 함수는 "테스트입니다."라는 문자열을 매개변수로 필요로 하기 때문에 문자열을 파라미터로 가지는 함수 대리자를 선언해 준다.
private delegate void OnControlChange(String buttonText);
그 후엔 이 delegate에 저장할 함수를 구현한다.
public void ControlChange(String buttonText){
if(this.InvokeRequired){
OnControlChange onControlChange = null;
onControlChange = new OnControlChange(ControlChange);
this.Invoke(onControlChange, buttonText);
}
else{
button1.Text = buttonText;
}
}
위의 코드를 보면 InvokeRequired라는 생소한 property가 나오는데, 이것은 요청을 한 쓰레드가 현재 메인 쓰레드에 있는 콘트롤을 엑세스 할 수 있는지 여부를 판단하기 위해 쓰였다고 보면 된다.
InvokeRequired가 true이면 현재 쓰레드는 메인쓰레드가 아니기 때문에 invoke와 delegate를 사용하여 메인쓰레드로 다시 호출을 해야한다.
막약 InvokeRequired가 false이면 현재 쓰레드는 메인쓰레드이므로 곧바로 콘트롤을 수정하면 된다.