WinForms에서 다른 스레드의 UI 컨트롤을 업데이트할 수 없는 이유는 무엇입니까?

StackOverflow https://stackoverflow.com/questions/10349

  •  08-06-2019
  •  | 
  •  

문제

나는 여기에는 타당한(또는 적어도 괜찮은) 이유가 있다고 확신합니다.그것은 무엇입니까?

도움이 되었습니까?

해결책

(다른 문제 중에서도) 쉽게 교착 상태에 빠질 수 있기 때문입니다.

예를 들어, 보조 스레드가 UI 컨트롤을 업데이트하려고 시도할 수 있지만 UI 컨트롤은 보조 스레드에 의해 잠긴 리소스가 해제될 때까지 기다리게 되므로 두 스레드는 결국 서로가 완료될 때까지 기다리게 됩니다.다른 사람들이 언급했듯이 이 상황은 UI 코드에만 국한된 것은 아니지만 특히 일반적입니다.

C++와 같은 다른 언어에서는 이 작업을 자유롭게 시도하고 수행할 수 있지만(WinForms에서처럼 예외가 발생하지 않음) 교착 상태가 발생하면 응용 프로그램이 멈추고 응답을 멈출 수 있습니다.

또한 컨트롤을 업데이트하고 싶다고 UI 스레드에 쉽게 알리고 대리자를 만든 다음 해당 컨트롤에서 (비동기) BeginInvoke 메서드를 호출하여 대리자를 전달하면 됩니다.예:

myControl.BeginInvoke(myControl.UpdateFunction);

이는 작업자 스레드에서 C++/MFC PostMessage를 수행하는 것과 동일합니다.

다른 팁

나는 이것이 훌륭한 질문이라고 생각합니다. 그리고 더 나은 대답이 필요하다고 생각합니다.

분명히 유일한 이유는 프레임 워크에 스레드 안전하지 않은 곳에 무언가가 있기 때문입니다.

해당 "무언가"는 System.Windows.Forms의 모든 단일 컨트롤에 있는 거의 모든 단일 인스턴스 멤버입니다.

System.Windows.Forms의 많은 컨트롤에 대한 MSDN 문서는 전부는 아니지만 다음과 같이 말합니다. "이 유형의 모든 공개 정적(Visual Basic에서는 공유) 멤버는 스레드로부터 안전합니다.모든 인스턴스 멤버는 스레드로부터 안전하다고 보장되지 않습니다."

이는 다음과 같은 인스턴스 멤버를 의미합니다. TextBox.Text {get; set;} 아니다 요각.

각 인스턴스 멤버를 스레드로부터 안전하게 만들면 대부분의 애플리케이션에 필요하지 않은 많은 오버헤드가 발생할 수 있습니다.대신 .Net 프레임워크의 디자이너는 여러 스레드에서 양식 컨트롤에 대한 액세스를 동기화하는 부담을 프로그래머에게 주어야 한다고 결정했으며 내 생각이 옳습니다.

[편집하다]

이 질문은 "왜"만을 묻지만 "어떻게"를 설명하는 기사에 대한 링크는 다음과 같습니다.

어떻게:Windows Forms 컨트롤에 대한 스레드로부터 안전한 호출 수행 MSDN에서

http://msdn.microsoft.com/en-us/library/ms171728.aspx

합리적으로 들리지만 John의 대답은 정확하지 않습니다.실제로 Invoke를 사용하는 경우에도 교착 상태 상황이 발생하지 않는 것은 여전히 ​​안전하지 않습니다.Invoke를 사용하여 백그라운드 스레드에서 실행된 이벤트를 처리할 때 이 문제가 발생할 수도 있습니다.


실제 이유는 경쟁 조건과 더 관련이 있으며 고대 Win32 시대로 거슬러 올라갑니다.여기서는 세부 사항을 설명할 수 없습니다. 키워드는 메시지 펌프, WM_PAINT 이벤트 및 "SEND"와 "POST" 사이의 미묘한 차이입니다.


자세한 내용은 여기에서 확인하세요 여기 그리고 여기.

1.0/1.1에서는 디버깅 중에 예외가 발생하지 않았습니다. 대신 간헐적인 런타임 중단 시나리오가 발생했습니다.멋진!:) 그러므로 2.0으로 그들은이 시나리오를 예외로 던졌습니다.

이에 대한 실제 이유는 아마도 (Adam Haile이 말했듯이) 일종의 동시성/잠금 문제일 것입니다.일반 .NET API(예: TextBox.Text = "Hello";)는 업데이트를 수행하는 스레드와 별도의 스레드에서 수행될 경우 문제를 일으킬 수 있는 SEND 명령(즉각적인 조치가 필요함)을 래핑합니다.Invoke/BeginInvoke를 사용하면 작업을 대기열에 넣는 대신 POST를 사용합니다.

SEND 및 POST에 대한 추가 정보 여기.

동시에 컨트롤을 업데이트하려고 하는 두 가지 작업이 없도록 하기 위한 것입니다.(CPU가 쓰기/읽기 중간에 다른 스레드로 전환하는 경우 발생할 수 있습니다) 여러 스레드간에 공유 변수에 액세스 할 때 MUTEXES (또는 일부 다른 동기화)를 사용해야하는 이유와 같은 이유가 발생합니다.

편집하다:

C ++와 같은 다른 언어에서는 자유롭게 시도 하고이 작업을 수행 할 수 있지만 (Winforms에서와 같이 예외없이) 어려운 방법을 배우게됩니다!

아 네...C/C++와 C# 사이를 전환했기 때문에 그랬어야 했던 것보다 좀 더 일반적이었습니다. 죄송합니다...그 사람 말이 맞아요, 당신은 ~할 수 있다 C/C++에서 이 작업을 수행하면 다시 짜증이 날 것입니다!

동시에 호출되는 데 민감한 업데이트 함수 내에서 동기화를 구현해야 할 수도 있습니다.UI 요소에 대해 이 작업을 수행하면 애플리케이션과 OS 수준 모두에서 비용이 많이 들고 대부분의 코드에 대해 완전히 중복됩니다.

일부 API는 시스템의 현재 스레드 소유권을 변경하는 방법을 제공하므로 스레드 간 통신에 의존할 필요 없이 다른 스레드에서 시스템을 일시적으로(또는 영구적으로) 업데이트할 수 있습니다.

흠 잘 모르겠지만 대기 막대, 진행 막대와 같은 진행률 컨트롤이 있으면 다른 스레드에서 해당 값을 업데이트할 수 있고 모든 것이 결함 없이 잘 작동한다고 생각합니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top