본문 바로가기

프로그래밍&IT/C#

[C#] Cross Threading 처리 : InvokeRequired 속성

UI 그리고 Thread 프로그래밍하다 간혹 "크로스 스레드" 문제를 부딪치게 되면서,

Invoke 및 Control.InvokeRequired 속성을 알아보게 되었습니다.

스레드들에 대해 약간 보자면...

- Thread Affinity(스레드 선호도) : 기본적으로 그 UI 컨트롤을 생성한 쓰레드만이 해당 UI객체를 접속 가능.

- UI 스레드 : UI 컨트롤을 생성하고 이 컨트롤의 윈도우 핸들을 소유한 스레드
- Worker 스레드 : 이런 UI 스레드를 갖지 않는 스레드

 

예제

using System.Threading;

namespace FrmEx10
{
    public partial class Form1 : Form
    {
        private Thread m_thread = null;
        
        public Form1()
        {
            InitializeComponent();
            
            m_thread = new Thread(new ThreadStart(ThreadProc));
            m_thread.Start();
        }
        
        private void ThreadProc()
        {
            int count = 0;

            while (true) {
                SetTextBox(count);
                count++;
                
                if (count == 10)
                    break;
            }
        }
        
        private void SetTextBox(int count)
        { //여기서 중단점 (F9)
            txtOutput.Text = count.ToString() + "번째";
   // 이부분에서
   //InvalidOperationException
   //크로스 스레드 작업이 잘못되었습니다. txtOutput컨트롤이 자신이 만들어진
   //스레드가 아닌 스레드에서 액세스되었습니다.  
        }
    }//Form1
}//namespace

이를 해결하기위해서 Control.InvokeRequired를 확인해야 한다.

 

InvokeRequired

- 다른 Thread로부터 호출되어 Invoke가 필요한 상태를 체크해서 true / false 리턴

- invoke가 필요한 상태일때,

  invoke메소드에 의해 호출될 델리게이트로 넘겨서 실행시키면 안정성있게 UI 갱신.

 

> 해당 컨트롤의 InvokeRequired 를 확인해서, true라면 delegate를 수행시킨다

public delegate void dgtSetBox(int count);    // 델리게이트 생성
private void SetTextBox(int count)
{
    if (textBox1.InvokeRequired)    //InvokeRequired가 true이면
	{
    	dgtSetBox dgt = new dgtSetBox(SetTextBox);
        this.Invoke(dgt, new object[] { count });
    }
    else
    {
        txtOutput.Text = count.ToString() + "번째";
    }
}