스레드로부터 안전한 방식으로 Windows Forms 컨트롤 호출



 프로그램이 조금 복잡해 지면 스레드를 사용하게 된다. WinForm 으로 멀티 스레드를 사용하다가 스레드가 컨트롤에 접근 하려 하면 예외가 발생한다. (역시 C# 컴파일러는 냉정하다...)



예외 : InvalidOperationException
설명 : "control name 컨트롤이 자신이 만들어진 스레드가 아닌 스레드에서 액세스되었습니다."

이 예외는 디버깅 할 때 발생하며, Run-time 때는 발생하지 않는다. (프로그램을 강제 종료 시키지도 않더라.)

CheckForIllegalCrossThreadCalls 프로퍼티 값을 false 로 설정하면 위 예외를 발생시키지 않게 할 수 있지만 안정적인 프로그램 작성을 위해 위 예외 처리 및, 예외가 일어 나지 않게 해주자.


테스트 한 코드는 다음과 같다.
#region 스레드메소드

// 스레드 메소드
public void ThreadProc()
{
            while (ThreadRun)
            {
                QueryCount++;
                QueryDB(QueryCount);                    
            }

            MessageBox.Show("스레드 작업 종료");
}


delegate void SetTextBox(int _count);

// 스레드에서 호출하는 메소드
private void QueryDB(int _count)
{
            var query = from c in TestDB.tbNodes
                              select c;

            RecordCount = query.Count();

            // textBoxQueryCount.Text = _count.ToString();
            // textBoxRecordCount.Text = RecordCount.ToString();
            // Thread.Sleep(RepeateCount * 1000);


            if (textBoxQueryCount.InvokeRequired)
            {
                SetTextBox dele = new SetTextBox(QueryDB);
                this.Invoke(dele, new object[] { _count });
            }
            else
                textBoxQueryCount.Text = _count.ToString();

            if (textBoxRecordCount.InvokeRequired)
            {
                SetTextBox dele = new SetTextBox(QueryDB);
                this.Invoke(dele, new object[] { _count });
            }
            else
                textBoxRecordCount.Text = RecordCount.ToString();

            Thread.Sleep(RepeateCount * 1000);
}
#endregion




부모 스레드에서 ThreadProc() 메소드를 작업자 스레드로 생성한다.
ThreadProc() 메소드는 ThreadRun 프로퍼티 값이 true 이면 계속 실행 하고, false 이면 스레드를 종료한다.

ThreadProc() 메소드를 실행하는 자식 스레드는 QueryDB() 메소드를 실행 하는데 이 안에서 컨트롤로 접근을
하게 된다.

컨트롤의 InvokeRequired 프로퍼티는 호출자가 컨트롤이 만들어진 스레드와 다른 스레드에 있기 때문에 메서드를 통해 컨트롤을 호출하는 경우 해당 호출자가 호출 메서드를 호출해야 하는지 여부를 나타내는 값을 가져온다.
컨트롤의 Handle 이 호출 스레드와 다른 스레드에서 만들어져 호출 메서드를 통해 해당 컨트롤을 호출해야 하는 경우 true이고, 그렇지 않으면 false이다.
cf) MSDN InvokeRequired : http://msdn.microsoft.com/ko-kr/library/system.windows.forms.control.invokerequired.aspx

InvokeRequired 값이 true 일 때는 delegate 를 이용하여 해당 컨트롤에 접근하는 메소드를 다시 호출해 주고,
false 일 때는 직접 호출해 준다.







참조)
1. MSDN
http://msdn.microsoft.com/ko-kr/library/ms171728%28VS.80%29.aspx





Posted by six605
,