Windows Forms 애플리케이션의 성능을 향상시키기 위해 멀티스레딩을 사용하는 경우 컨트롤이 스레드로부터 안전한 방식으로 호출되는지 확인해야 합니다.
Windows Forms 컨트롤에 액세스하는 것은 본질적으로 스레드로부터 안전하지 않습니다. 컨트롤의 상태를 조작하는 스레드가 두 개 이상인 경우 컨트롤을 일관성 없는 상태로 만들 수 있습니다. 경쟁 조건 및 교착 상태와 같은 다른 스레드 관련 버그가 발생할 수 있습니다. 스레드로부터 안전한 방식으로 컨트롤에 액세스해야 합니다.
1. 초보자가 자주 겪는 문제
컨트롤을 생성하기 위해 Invoke 메서드를 사용하지 않은 스레드에서 컨트롤을 호출하는 것은 안전하지 않습니다. 다음은 스레드로부터 안전하지 않은 호출의 예입니다. InvalidOperationException 메시지는 런타임 중에 "컨트롤을 생성하지 않은 스레드에서 컨트롤 컨트롤 이름에 액세스했습니다."라는 오류와 함께 발생합니다.
// This event handler creates a thread that calls a // Windows Forms control in an unsafe way.private void setTextUnsafeBtn_Click( object sender, EventArgs e) { this.demoThread = new Thread(new ThreadStart(this.ThreadProcUnsafe)); this.demoThread.Start(); }// This method is executed on the worker thread and makes// an unsafe call on the TextBox control.private void ThreadProcUnsafe() { this.textBox1.Text = "This text was set unsafely."; }
2. 해결 방법
Windows Forms 컨트롤에 대해 스레드로부터 안전한 호출을 수행해야 하는 경우.
①컨트롤의 InvokeRequired 속성을 쿼리합니다.
②InvokeRequired가 true를 반환하면 실제 호출 제어의 위임자를 사용하여 Invoke를 호출합니다.
③InvokeRequired가 false를 반환하는 경우 컨트롤을 직접 호출하세요.
여기서는 동기 실행 위임과 비동기 실행 위임으로 구분됩니다.
다음 코드 예제에서는 백그라운드 스레드에 의해 실행되는 ThreadProcSafe 메서드에서 스레드로부터 안전한 호출이 구현됩니다. TextBox 컨트롤의 InvokeRequired가 true를 반환하는 경우 ThreadProcSafe 메서드는 SetTextCallback 인스턴스를 만들고 이를 양식의 Invoke 메서드에 전달합니다. 이렇게 하면 TextBox 컨트롤을 만든 스레드에서 SetText 메서드가 호출되고 Text 속성이 해당 스레드의 컨텍스트에서 직접 설정됩니다.
// This event handler creates a thread that calls a // Windows Forms control in a thread-safe way. private void setTextSafeBtn_Click( object sender, EventArgs e) { this.demoThread = new Thread(new ThreadStart(this.ThreadProcSafe)); this.demoThread.Start(); }// This method is executed on the worker thread and makes // a thread-safe call on the TextBox control. private void ThreadProcSafe() { this.SetText("This text was set safely."); }// This delegate enables asynchronous calls for setting // the text property on a TextBox control.delegate void SetTextCallback(string text); // This method demonstrates a pattern for making thread-safe // calls on a Windows Forms control. // // If the calling thread is different from the thread that // created the TextBox control, this method creates a // SetTextCallback and calls itself asynchronously using the// Invoke method. // // If the calling thread is the same as the thread that created // the TextBox control, the Text property is set directly. private void SetText(string text) { // InvokeRequired required compares the thread ID of the // calling thread to the thread ID of the creating thread. // If these threads are different, it returns true. //this.textBox1.InvokeRequired will be replaced by //this.InvokeRequired, if want to set many controls' //attribute or text. if (this.textBox1.InvokeRequired)// or this.InvokeRequired { SetTextCallback d = new SetTextCallback(SetText); this.Invoke(d, new object[] { text }); } else { this.textBox1.Text = text; } }
3.BackgroundWorker 구성 요소
애플리케이션에서 멀티스레딩을 구현하는 가장 좋은 방법은 BackgroundWorker 구성 요소를 사용하는 것입니다. BackgroundWorker 구성 요소는 다중 스레드 처리를 위해 이벤트 기반 모델을 사용합니다. 백그라운드 스레드는 DoWork 이벤트 처리기를 실행하고 컨트롤을 만든 스레드는 ProgressChanged 및 RunWorkerCompleted 이벤트 처리기를 실행합니다. ProgressChanged 및 RunWorkerCompleted 이벤트 핸들러에서 컨트롤을 호출할 수 있습니다.
①백그라운드 스레드에서 하고 싶은 작업을 수행하기 위한 메서드를 만듭니다. 이 메서드의 기본 스레드에서 생성된 컨트롤을 호출하지 마세요.
②백그라운드 작업이 종료된 후 백그라운드 작업 결과를 보고하는 메소드를 만듭니다. 메인 스레드에 의해 생성된 컨트롤은 이 메서드에서 호출될 수 있습니다.
③ 1단계에서 생성한 메서드를 DoWork 인스턴스의 BackgroundWorker 이벤트에 바인딩하고, 2단계에서 생성한 메서드를 동일한 인스턴스의 RunWorkerCompleted 이벤트에 바인딩합니다.
④ 백그라운드 스레드를 시작하려면 RunWorkerAsync 인스턴스의 BackgroundWorker 메서드를 호출합니다.
다음 코드 예제에서 DoWork 이벤트 핸들러는 Sleep을 사용하여 시간이 걸리는 작업을 시뮬레이션합니다. 양식의 TextBox 컨트롤을 호출하지 않습니다. TextBox 컨트롤의 Text 속성은 RunWorkerCompleted 이벤트 핸들러에서 직접 설정됩니다.
// This BackgroundWorker is used to demonstrate the // preferred way of performing asynchronous operations.private BackgroundWorker backgroundWorker1; // This event handler starts the form's // BackgroundWorker by calling RunWorkerAsync. // // The Text property of the TextBox control is set // when the BackgroundWorker raises the RunWorkerCompleted // event.private void setTextBackgroundWorkerBtn_Click( object sender, EventArgs e) { this.backgroundWorker1.RunWorkerAsync(); }// This event handler sets the Text property of the TextBox // control. It is called on the thread that created the // TextBox control, so the call is thread-safe. // // BackgroundWorker is the preferred way to perform asynchronous // operations.private void backgroundWorker1_RunWorkerCompleted( object sender, RunWorkerCompletedEventArgs e) { this.textBox1.Text = "This text was set safely by BackgroundWorker."; }
ProgressChanged 이벤트를 사용하여 백그라운드 작업의 진행 상황을 보고할 수도 있습니다. 이 이벤트를 포함하는 예제는 BackgroundWorker를 참조하세요.
위 내용은 0-자식 스레드에서 메인 스레드(UI 스레드) 제어에 액세스하는 C#02의 자체 학습 내용입니다. 더 많은 관련 내용은 PHP 중국어 웹사이트(www. php.cn)!