Invoke , BeginInvoke, MethodInvoker
Invoke, MethodInvoker, BeginInvoke - EndInvoke
Introduction
UI Control들은 폼 구동시 실행되는 하나의 쓰레드에서 구동된다. 따라서 사용자가 실행시킨 쓰레드는 별도로 실행 되기 때문에 이 메인 쓰레드에 적절한 마샬링 없이 다른쓰레드에서 직접 접근하면 다른 쓰레드를 침범하는 것이다. (Cross Thread Problem) 이런 경우에는 프로그램이 개발자가 설계한대로 잘 동작하지 않을 수 있다.(Race Condition,DeadLock) 따라서, 안전하게 동작하게 하기위하여 .Net 환경에서는 Invoke를 제공하고 있다.
본 내용을 무시한 채 프로그램을 작성하면 InvalidOperationException을 발생시키고 . Debug 창에서 "컨트롤이 자신이 만들어진 스레드가 아닌 스레드에서 액세스되었습니다."라는 메세지가 표시 된다. 하지만 디버깅 환경이 아니라면 프로그램은 겉보기에 정상 동작하는 것 처럼 보일 수 있으므로 조심해야 된다. !
난 대충 좀 안되도 상관 없다고 생각하시는 분들은 이 예외를 비활성화 할 수도 있습니다.
CheckForIllegalCrossThreadCalls 속성 값을 false로 설정하여 이 예외를 비활성화할 수 있습니다. 그러면 컨트롤이 Visual Studio 2003에서와 같은 방식으로 실행됩니다.
이 노트에서 학습하실 때 유념하셔야 될 내용은
- Control Invoke 와 Delegate Invoke의 차이점을 숙지한다.
- Invoke와 BeginInvoke의 차이점과 사용법을 숙지한다.
자 그럼 쓰레드에서 안전하게 Windows Form control을 제어하게 하는 방법에 대해 알아보자.
우선, InvokerRequired 를 알고 시작하자. 이 속성은 Invoke메쏘드를 호출해야되는 상황인지 알려준다.
Invoke
쓰레드에서 폼 컨트롤 하기 위해서는 별도의(SetTextononTextBox1) 메쏘드를 만들어 사용하면 좋다. 예를들어, Textbox에 값을 입력한다면 아래와 같은 'SetTextonTextBox1' 메쏘드를 만들어서 사용하면 Cross thread 환경이든 내부 쓰레드 사용환경에서든 둘다 사용할 수 있다. 또는 Delegate 메쏘드가 FormControl을 인자로 받아서 사용할 수도 있다.
Invoke를 사용할 때 인자를 넘겨줘야 하는 메쏘드 필요하면 할때는 반드시 delegate를 선언한 후에 사용하여야 한다.
- delegate void SetTextCallback(string txt);
private void SetTextonTextBox1(string txt)
{
if (this.textBox1.InvokeRequired)
{
this.Invoke(new SetTextCallback(SetTxtCB), new object[] { txt }); //그냥 txt를 넘겨줘도 된다
}
else
{
this.textBox1.Text += txt;
}
}
private void SetTxtCB(string txt)
{
this.textBox1.Text+=txt;
}
- public delegate void UpdateText(Control ctrl, string text);
public void UpdateTextFunc(Control ctrl, string text)
{
if (ctrl.InvokeRequired)
{
ctrl.Invoke(new UpdateText(UpdateTextFunc), new object[] { ctrl, text });
}
else
ctrl.Text += text;
}
인자가 없는 메쏘드를 호출할 때는 간단하게 MethodInvoker를 사용하면 좋다.
- private void SetTextonTextBox1(string txt)
{
if (this.textBox1.InvokeRequired)
{ this.Invoke(new MethodInvoker( delegate { this.textBox1.Text+=txt; }) );
}
else
{
this.textBox1.Text += txt;
}
}
BeginInvoke , EndInvoke
우선 BeginInvoke를 설명하기 전에 Windows Form 의 Control.BeginInvoke 메쏘드와 Delegate.BeginInvoke 메쏘드에 대해서 차이점을 설명하고 본 단락에서는 Winfows Form Control의 BeginInvoke만 설명하도록 하겠다.
Delegate.BeginInvoke는 Asynchronous Delegate를 만들어서 콜백을 하는 것이라고 생각하면 되겠다. 다시말해서, CLR에서 관리하는 쓰레드풀에서 해당 메쏘드를 큐잉한다. 쉽게 얘기해서 별도의 쓰레드를 만들어서 Delegate를 실행한다고 보면 된다. 장점은 IAsyncResult를 이용해서 Object 결과값을 넘겨 받을 수 있다. 보다 자세한 사항은 이곳을 참조!
Windows Form의 Control.BeginInvoke는 Control 내부 핸들이 작성된 쓰레드(메인쓰레드)에서 지정된 대리자를 비동기식으로 실행한다. 비동기식이므로 실행을 대기하지 않고 BeginInvoke는 즉시 Return 한다.
차이점을 정리 하자면 Control.BeginInvoke는 실행코드의 GUI Thread에 작성된 코드이고 Delegate.BeginInvoke는 쓰레드풀 쓰레드에 사용된다. 또한 Control.BeginInvoke의 경우는 EndInvoke를 호출하지 않아도 되나 Delegate.BeginInvoke의 경우는 반드시 Delegate.EndInvoke를 호출해줘야 한다 안그러면 메모리 릭이 발생한다.
- public delegate void InvokeDelegate();
- private void Invoke_Click(object sender, EventArgs e)
{
myTextBox.BeginInvoke(new InvokeDelegate(InvokeMethod));
}
public void InvokeMethod()
{
myTextBox.Text = "Executed the given delegate";
}
Endinvoke
Reference
- http://msdn.microsoft.com/ko-kr/library/ms171728.aspx
- http://xmlangel.textcube.com/6
- http://jongkok4.net/entry/펌c-UI-쓰레드-마샬링-Invoke-BeginInvoke?TSSESSIONjongkok4net=6e5ec00b34c31e0126e9a64412f7a627
- http://timl.net/2008/01/begininvoke-methodinvoker-and-anonymous.html
- http://shiman.wordpress.com/2008/09/10/c-net-delegates-asynchronous-invocation-begininvoke-method/
- http://msdn.microsoft.com/ko-kr/library/0b1bf3y3(VS.80).aspx
- http://kristofverbiest.blogspot.com/2007/02/don-confuse-controlbegininvoke-with.html
- http://www.albahari.com/threading/#_Introduction
- http://www.yoda.arachsys.com/csharp/threadstart.html
'Programming > C#' 카테고리의 다른 글
Loaded(로드완료) 이벤트 (0) | 2012.07.16 |
---|---|
윈폼기반 프로그래밍을 할때 Invoke() 이쁘게쓰기! (0) | 2012.06.10 |
GetWindowRect - Window의 위치및 크기 반환 (0) | 2012.06.01 |
파일경로 지정 및 디렉토리 지정 FolderBrowserDialog (0) | 2012.05.25 |
좌표에서 RGB값 받아오기 (0) | 2012.05.24 |