크로스 스레드 에러
스레드에서 직접 컨트롤을 접근하게 되면 크로스 스레드 에러가 발생합니다.
스레드에서 컨트롤을 접근하는 것은 컨트롤을 일관되지 않은 상태로 만들 수 있고, 심각한 오류나 프로그램 중단을 초래할 수 있습니다.
따라서 스레드에서 직접 컨트롤을 접근하는 것은 안전하지 않은 호출 방법입니다.
다음은 크로스 스레드 에러를 발생시키는 예제 코드입니다.
private void Button1_Click(object sender, EventArgs e)
{
thread = new Thread(SetName);
thread.Start();
}
private void SetName()
{
txtName.Text = "SSABI"; // 크로스 스레드 에러 발생!
}
크로스 스레드 에러를 해결하게 위해서는 System.Windows.Forms.Control.Invoke 또는
System.ComponentModel.BackgroundWorker를 사용해야 합니다.
크로스 스레드 에러를 해결하는 2가지 방법을 설명드리겠습니다.
1. Invoke
스레드에서 델리게이트(Delegate)를 사용해서 메소드를 호출하는 방법입니다.
다음은 Invoke를 사용하는 예제 코드입니다.
public class Form1 : Form1
{
private delegate void SetTextSafeDelegate(string text);
private Thread thread = null;
private void Button1_Click(object sender, EventArgs e)
{
thread = new Thread(SetText);
thread.Start();
}
private void SetTextSafe(string text)
{
if(textBox1.InvokeRequired)
{
SetTextSafeDelegate del = new SetTextSafeDelegate(SetTextSafe);
textbox1.Invoke(del, new object[]{text});
}
else
{
textbox1.Text = text;
}
}
private void SetText()
{
SetTextSafe("Use Invoke");
}
}
스레드에서 호출할 델리게이트를 정의하고 Invoke를 사용하여 델리게이트를 호출합니다.
InvokeRequired는 다른 스레드로부터 호출되었을 경우 Invoke를 사용 해야 하는지 여부를 알려줍니다.
InvokeRequired가 true일 경우 Invoke를 사용해서 델리게이트를 넘겨 주어야 하고,
false일 경우 직접 컨트롤을 접근할 수 있습니다.
Invoke 메소드의 인자는 Invoke(delegate 델리게이트, object[] 파라미터)로 넘겨줍니다.
2. BackgroundWorker
스레드에서 BackgroundWorker 클래스를 사용하는 방법입니다.
BackgroundWorker는 UI 스레드와는 별도로 백그라운드에서 비동기적 작업을 수행하는데 사용됩니다.
다음은 BackgroundWorker를 사용하는 예제 코드입니다.
public partial class Form1 : Form
{
private BackgroundWorker backgroundWorker;
public Form1()
{
InitializeComponent();
backgroundWorker = new BackgroundWorker();
backgroundWorker.DoWork += new DoWorkEventHandler(BackgroundWorkerDoWork);
backgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(BackgroundWorkerRunWorkerCompleted);
}
private void button1_Click(object sender, EventArgs e)
{
backgroundWorker.RunWorkerAsync();
}
private void BackgroundWorkerDoWork(object sender, DoWorkEventArgs e)
{
Thread.Sleep(1000); e.Result = "Use BackgroundWorker";
}
private void BackgroundWorkerRunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
lblText.Text = e.Result.ToString();
}
}
BackgroundWorker 객체를 생성합니다.
BackgroundWorke의 DoWork에 백그라운드 스레드에서 수행하는 메소드를 이벤트 핸들러에 등록하고,
RunWorkerCompleted에 DoWork 작업이 모두 끝났을 때 처리하는 메소드를 이벤트 핸들러에 등록합니다.
DoWork의 작업이 완료되면 Result에 결과를 대입해 주고 RunWorkerCompleted에서 컨트롤에
RunWorkerAsync()를 호출하면 DoWork가 실행됩니다.
출처: https://ssabi.tistory.com/37 [싸비]
'개발언어 > C#' 카테고리의 다른 글
(c#) WinForm 창 크기 조절하기 (0) | 2020.11.20 |
---|---|
(c#) 폼의 크기가 변할때, 컨트롤의 사이즈및 위치 (0) | 2020.11.20 |
[C#] #region / #endregion 접기/펼치기 (0) | 2020.11.06 |
[C#] C#과 C API의 상호운영 dll사용등 (0) | 2020.11.04 |
[c#] [C++] --> [C#] 구조체, 클래스 컨버팅 (0) | 2020.11.04 |