#1프로그래밍/#5 C#

[C#, Winform, 에러, InvokeRequired ] System.InvalidOperationException: 크로스 스레드 작업이 잘못되었습니다

HopeDeveloper 2022. 11. 23. 18:45

1. 에러 발생

System.InvalidOperationException: 크로스 스레드 작업이 잘못되었습니다. 'label_Connection' 컨트롤이 자신이 만들어진 스레드가 아닌 스레드에서 액세스되었습니다.

   위치: System.Windows.Forms.Control.get_Handle()

   위치: System.Windows.Forms.Control.set_WindowText(String value)

   위치: System.Windows.Forms.Control.set_Text(String value)

 

2. 원인 분석
- 멀티 쓰레드 환경에서 Winform 컨트롤을 다른 스레드에서 접근할 때 발생
- 현재 Thread에서 실시간으로 UI를 변경하는 부분이 존재

    //4. Simulation Thread 실행
    SimCore.worker = new Thread(UpdateDataGrid);
    SimCore.worker.IsBackground = true;
    SimCore.worker.Start();

UpdateDataGrid() 쓰레드 내에서 UI를 변경하는 경우 발생

-->  label_Connection.Text = string.Format("Connected ({0})", connection_count);

 

3. 해결 방법

 - InvokeRequired : 호출자가 컨트롤이 만들어진 스레드(메인스레드)와 다른 스레드에 있기 때문에 메서드를 통해 호출해야하는지 판단 (True 인 경우 충돌 발생)

 - Invoke : 컨트롤을 생성한 스레드에서 동기식으로 실행 (메인 쓰레드에게 함수 호출을 위임)
- BeginInvoke : 비동기식으로 실행

private void UpdateDataGrid()
{
    ConfigManager.log.Info("Form_Main.UpdateDataGrid() - Thread UpdateDataGrid() Start.");
    int connection_count = 0;

    while (true)
    {
        try
        {           
			//......다른 Logic
                    if(label_Connection.InvokeRequired)
                    {
                        label_Connection.BeginInvoke(new Action(() => label_Connection.Text = string.Format("Connected ({0})", connection_count)));
                        connection_count = SimCore.IedServer.GetNumberOfOpenConnections();
                    }
                    else
                    {
                        label_Connection.Text = string.Format("Connected ({0})", connection_count);
                    }
                    string msg = string.Format("Current Connection Count = {0}", connection_count);
                    ConfigManager.log.Debug(msg);
                }
            }

			//... 
    }
}